home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / FLEXFILE.ARJ / FLEXINFO.EXE / FLEXFILE.DOC < prev    next >
Text File  |  1991-10-22  |  195KB  |  5,663 lines

  1.  
  2.  
  3.                                FlexFile■
  4.                  (C) Copyright 1990 Ganahl Software
  5.                           All Rights Reserved
  6.  
  7.  
  8.  
  9.    This document is supplied as an introduction to FlexFile.  Although it
  10.    contains almost all of the FlexFile documentation, it is not part of the
  11.    FlexFile commercial package.  Please feel free to distribute this file
  12.    freely to any interested party.
  13.  
  14.    This does NOT imply that files in the .OBJ format or .LIB format from
  15.    the FlexFile commercial package may be distributed in any manner.
  16.  
  17.  
  18.  
  19.  
  20.    GANAHL Software
  21.    P.O. Box 4275
  22.    Deerfield Beach, Fl 33442
  23.    Tel: (305) 566-1796
  24.    Fax: (305) 566-3517
  25.  
  26.  
  27.  
  28.                        Overview
  29.  
  30.  
  31.    Variable Length Fields
  32.  
  33.    FlexFile is a very focused dual purpose tool kit for Clipper
  34.    programmers.  Its first and main purpose is to provide a
  35.    complete replacement for Clipper's memo-fields with a more
  36.    powerful and more efficient Variable Length Field engine.  We
  37.    are certain that it will relieve you of the confinement
  38.    imposed by Clipper's memo-fields, but also, we believe it may
  39.    change the way you think about your data base structures in
  40.    general.
  41.  
  42.    FlexFile was designed to be immediately familiar to the
  43.    Clipper programmer. To accomplish this goal, many of the
  44.    function names can only be distinguished from their Clipper
  45.    counterpart by a V_ prefix.  For example, V_USE() opens a DBV
  46.    file in the currently V_SELECT()ed work area.
  47.  
  48.    The similarities extend into the structural use of FlexFile's
  49.    Variable Length Fields (VLF) as well.  FlexFile's version of a
  50.    memo-field (which we will refer to as a pointer-field) is a
  51.    six byte character type field in a DBF file. FlexFile uses
  52.    this pointer-field to store a pointer to variable length data
  53.    in a .DBV file (FlexFile's version of a .DBT file).  These
  54.    similarities allow any Clipper REPLACE syntax which works on
  55.    memo-fields to remain almost unchanged when used with
  56.    FlexFile.  This claim carries in network environments as well.
  57.  
  58.    The benefits and use of FlexFile's Variable Length Fields are
  59.    discussed in detail in the Reference "Variable Length Fields".
  60.    Pay special attention to the section on FlexFile's extended
  61.    features.
  62.  
  63.  
  64.  
  65.    Arrays
  66.  
  67.    FlexFile's strongly typed arrays provide a utility which defy
  68.    the products name.  Instead of being flexible, these arrays
  69.    are purposefully rigid.  The utility of these arrays is
  70.    twofold.  First and foremost, they use far less space than
  71.    their Clipper counterpart.  For example, any Clipper array of
  72.    1,000 elements would require a minimum of 14,000 bytes from
  73.    Clipper's free pool of memory.  A FlexFile array of 1,000
  74.    integers, on the other hand, would require only 2,000 bytes
  75.    from Clipper's free pool of memory.
  76.  
  77.    Typically, large strongly typed arrays are used for scientific
  78.    or statistical matrixes.  For this reason, FlexFile provides a
  79.    host of functions which globally manipulate or query these
  80.    large arrays.
  81.  
  82.  
  83.  
  84.  
  85.    Linking FlexFile into an application
  86.  
  87.    FlexFile is compatible with all the linkers that it has been
  88.    tested with.  The entire library can be overlayed with
  89.    Blinker(tm) or WarpLink(tm) or RTLink Plus(tm).
  90.  
  91.    The procedure for linking is the same as for any other library
  92.    listed in your link file or on the link command line.  For
  93.    example:
  94.  
  95.     link test.obj,,,c:\lib\clipper c:\lib\flexfile
  96.  
  97.    Each FlexFile function begins with either a V_ or an A_
  98.    depicting use with the Variable Length Field manager or the
  99.    array manager, respectively.  The prefix to each function was
  100.    chosen to avoid conflict with other libraries.  If you find a
  101.    conflict with another library, you must place FlexFile before
  102.    the other library in the link list in order to use the
  103.    FlexFile function.  If you find a conflict please contact us
  104.    so that we may avoid them in future releases.
  105.  
  106.  
  107.  
  108.  
  109.  
  110.                     Variable Length Fields
  111.  
  112.    The enhancements to memo-fields
  113.  
  114.    FlexFile addresses the four major problems that plague
  115.    Clipper's implementation of memo-fields.
  116.  
  117.    First, FlexFile reuses all unused space.  If your user edits a
  118.    memo (or deletes elements of an array) making it smaller,
  119.    FlexFile is aware of every byte of the excess space and will
  120.    use it later for new data.  This feature totally eliminates
  121.    the file bloat that characterizes Clipper's DBT files.
  122.    (Clipper frequently abandons space no longer needed by
  123.    memo-field data, and once abandoned, not even packing the file
  124.    can regain the space.)
  125.  
  126.    Second, FlexFile does not allocate space in blocks.  Instead,
  127.    each item stored requires only the space for its own length
  128.    plus a six byte header that FlexFile uses for management.
  129.    This is in great contrast to Clipper's memo-fields that
  130.    require a fixed block size of 512 bytes.  This feature alone
  131.    will save disk space at an average of 256 bytes per record.
  132.  
  133.    Third, the size of FlexFile's Variable Length Field (VLF)
  134.    files are limited only by your disk space.  This is in
  135.    contrast to Clipper's size limit on a DBT file of 16M.
  136.  
  137.    Finally, FlexFile can store any valid Clipper data.  This
  138.    includes arrays, character strings, dates, numerics and
  139.    logicals.  In addition, the content of character data is not
  140.    limited as it is in Clipper.  It is, therefore, possible to
  141.    store SAVESCREEN() variables or any other binary data that you
  142.    use.
  143.  
  144.  
  145.  
  146.  
  147.    FlexFile's Extended Features
  148.  
  149.    Through FlexFile's ability to save an array to a field, your
  150.    DBF's can become three dimensional (actually multi-dimensional
  151.    with Clipper 5.0).  Looking at it another way, each record can
  152.    now have a variable number of fields.  This new feature allows
  153.    far greater flexibility in designing a database system.
  154.  
  155.    Lets take the simple example of storing a telephone number.
  156.    In a customer data base, next to the name and address we store
  157.    the telephone number.  But is one telephone number enough?
  158.    Most businesses require at least a voice line and a fax line.
  159.    Then again, there is that one guy who has got two voice lines,
  160.    a fax line, a data line, and a whole bunch more at his house.
  161.  
  162.    So, do we build in five or ten telephone fields in the
  163.    customer file?  Certainly this situation would not warrant a
  164.    second file and an index with a relation. Usually, we tell our
  165.    client (very nicely) to live with a maximum of two.
  166.  
  167.    With FlexFile, however, the answer is simple.  Save an array
  168.    of telephone numbers.  Those customers who have one or two
  169.    telephone numbers use only the space for one or two telephone
  170.    numbers.  Those that have ten can have ten. There are no
  171.    indexes or relations to maintain and you can extend this
  172.    concept into those perplexing data item which your client
  173.    defines as requiring "usually two or three, but sometimes
  174.    twenty or more".
  175.  
  176.    FlexFile also allows the programmer to store any valid Clipper
  177.    data type to a field.  At first look, this alternative seems
  178.    less than impressive.  Why would you want to store a logical
  179.    value, which takes only one byte per record in a DBF file, by
  180.    using a six byte pointer-field in the DBF to point to an
  181.    object which requires a six byte header in the DBV.  The
  182.    advantage does not come from saving any one type, but rather,
  183.    from being able to store different types to the same field.
  184.    This is particularly advantageous in data driven applications.
  185.    For example, if you give your clients user defined fields,
  186.    they can change the type of a field and you won't have to
  187.    worry about carrying extra fields for each type "Just in
  188.    Case".
  189.  
  190.  
  191.  
  192.  
  193.    USEing DBV files
  194.  
  195.    The use of FlexFile's DBV files was designed to parallel the
  196.    use of DBF type files.  Specifically, the system is made up of
  197.    work areas that are used to manage the VLF files in exactly
  198.    the same manner as Clipper uses work areas to manage DBF
  199.    files.  This method avoids the need to keep track of
  200.    "handles", and allows the use of aliases.
  201.  
  202.    For example, you can V_SELECT(1) and then V_USE() a file in
  203.    area one, and then V_SELECT(0) the next available work area
  204.    and V_USE() another file there.  It should be noted that
  205.    FlexFile's work areas are mutually exclusive from Clippers DBF
  206.    work areas.  For example, you can V_SELECT(1) and V_USE() a
  207.    file in VLF area one, and simultaneously, SELECT 1 and USE a
  208.    file in DBF area one with no conflicts.
  209.  
  210.    The FlexFile system offers an unlimited number of work areas,
  211.    however, you must decide what your maximum number of work
  212.    areas will be before you open the first DBV type file.  The
  213.    reason for this is to allow the system to create one
  214.    contiguous block of memory for the management of the files
  215.    instead of fragmenting memory with little blocks each time you
  216.    open a new file.  At any point that you have all DBV files
  217.    closed you can readjust this maximum number of work areas by
  218.    using the V_FILES() function.
  219.  
  220.  
  221.    Creating DBV files
  222.  
  223.    The simplest thing to do in FlexFile is to create a DBV type
  224.    file.  Simply V_USE() a file that does not exist and you will
  225.    have a DBV file open and ready to go.
  226.  
  227.  
  228.    How to Manage Your Data with FlexFile
  229.  
  230.    Another great use for FlexFile is to hold data that is not
  231.    repetitive and structured;  the DBF file structure is not at
  232.    all accommodating in this area.  For example, almost every
  233.    Clipper application requires system data such as a color
  234.    scheme, default directories, default drive for temporary
  235.    files, printer definitions, and other randomly sized
  236.    non-repetitive data.  Storing this data is now a trivial
  237.    matter.
  238.  
  239.    In this case, the design could be as simple as a two field DBF
  240.    file with an index, and one FlexFile VLF file.  The DBF
  241.    structure might look like:
  242.  
  243.        Structure for database: C:\FF\SYSTEM.DBF
  244.        Number of data records:      20
  245.        Date of last update   : 10/05/90
  246.        Field  Field Name  Type       Width    Dec
  247.            1  VAR_NAME    Character     10
  248.            2  VLF_FLD     Character      6
  249.        ** Total **                      17
  250.  
  251.    The key field <var_name> will hold the name of a Clipper
  252.    variable that you use; the six byte character field <vlf_fld>
  253.    FlexFile will use to hold a pointer to <var_name>'s value.
  254.    Following from the above description, start-up code for an
  255.    application might look like:
  256.  
  257.        // Declare the system wide public variables that you use.
  258.        PUBLIC aColors,;       // Array variable for colors
  259.               cDefaultDir,;   // A user defined default directory
  260.               dYearEnd        // A user defined year end date.
  261.  
  262.        //  Open the DBF, its index, and the VLF
  263.        USE System.dbf INDEX System.ntx
  264.        V_USE( "System.dbv" )
  265.  
  266.        //  Seek your colors array and retrieve it.
  267.        //  Note that this Clipper 5.0 syntax for arrays is slightly
  268.        //  different than the S'87 syntax.  See the V_FILLARR() function.
  269.        SEEK "aColors"
  270.        aColors = V_RETRIEVE( vlf_fld )
  271.  
  272.        //  Seek the record that holds a "Default" directory.
  273.        SEEK "cDefaultDir"
  274.        cDefaultDir = V_RETRIEVE( vlf_fld )
  275.  
  276.        //  Dates can be stored as easily as anything else.
  277.        SEEK "dYearEnd"
  278.        dYearEnd = V_RETRIEVE( vlf_fld )
  279.  
  280.    Of course, for this code to work you must have previously save
  281.    data to these records.  The next section on FlexFile's
  282.    pointers gives an in depth view into storing the data,
  283.    retrieving it and replacing old data with new.
  284.  
  285.  
  286.  
  287.    FlexFile's Pointers
  288.  
  289.  
  290.    The key to maintaining secure data with FlexFile is fully
  291.    understanding the pointers that FlexFile uses to access data.
  292.    Clipper's memo-fields maintains a similar set of pointers but
  293.    Clipper hides them from the programmer as well as the user.
  294.    If you try to assign a Clipper memo-field pointer directly to
  295.    a variable as in:
  296.  
  297.    var = system->mem_fld      // Clipper memo-field
  298.  
  299.  
  300.    Clipper intercepts the call and automatically goes to the DBT
  301.    file and fetches the data that <mem_fld> points to.  With
  302.    FlexFile, this assignment would put the pointer into <var>
  303.    instead of the data.  So, the equivalent code using flexfile
  304.    is:
  305.  
  306.        var = V_RETRIEVE( system->vlf_fld )    // FlexFile VLF
  307.  
  308.  
  309.    What we are doing here is passing the V_RETRIEVE() function a
  310.    pointer to the data and V_RETRIEVE() is kindly passing us back
  311.    data that was stored there.
  312.  
  313.    The same principal applies to saving data... with a twist.
  314.    When Clipper saves data to a memo-field, it allocates disk
  315.    space in 512 byte chunks and sticks a pointer to the allocated
  316.    space in the memo-field of the DBF file.  For example,
  317.  
  318.        // Clipper hogs 512 bytes with this one.
  319.        REPLACE system->mem_fld WITH "This will take 512 bytes"
  320.  
  321.    Clipper allocates 512 bytes of disk space, puts the 24 bytes
  322.    of data in the front of the new space, and puts a pointer to
  323.    the block in <mem_fld>.  If, without moving the record
  324.    pointer, we say
  325.  
  326.        // Clipper abandons the first mess and requires 1024 more.
  327.        REPLACE system->mem_fld WITH SPACE( 513 )
  328.  
  329.    then Clipper will abandon the first 512 byte block
  330.    (permanently), and allocate 1024 bytes for the new data.  The
  331.    old pointer to the 512 byte block is lost and the file space
  332.    is gone forever.
  333.  
  334.    FlexFile is smarter than this.  Using FlexFile, we would save
  335.    the 24 byte string with:
  336.  
  337.  
  338.        // FlexFile neatly allocates 30 bytes of disk space.
  339.        REPLACE system->vlf_fld WITH ;
  340.           V_REPLACE( "This will take  30 bytes", system->vlf_fld )
  341.  
  342.    If we follow the pointer in this example, we can see what
  343.    FlexFile is going to do.  The first thing that we notice is
  344.    that we not only pass to the V_REPLACE() function the new
  345.    data, but also, we give it the old pointer.
  346.  
  347.    Because this function will operate from right to left, first
  348.    it will look at the right most <vlf_fld> to see if it is
  349.    pointing to any old data.  If it is not, then the function
  350.    proceeds to look through an internal table for other vacated
  351.    space. We will assume for this example that this is the first
  352.    V_REPLACE(). Therefore, there is no available space that has
  353.    already been release by other data, so the new string is
  354.    appended to the end of the file.
  355.  
  356.    To do this FlexFile will allocate 30 bytes of disk space, 24
  357.    bytes for the data and six bytes to keep some information that
  358.    it uses for management.
  359.  
  360.    Now we continue the example by replacing the thirty bytes with
  361.    513 bytes of spaces:
  362.  
  363.        // FlexFile releases 30 bytes and stores 519.
  364.        REPLACE system->vlf_fld WITH ;
  365.              V_REPLACE( SPACE( 513 ), system->vlf_fld )
  366.  
  367.    This time, FlexFile sees that the old pointer has something in
  368.    it, and so releases it.  Then it seeks internally for an
  369.    available 519 byte space to put the new information.  There is
  370.    none, so it tags this at the end of the file as well.
  371.  
  372.    There are two very important advantages you can see from this
  373.    example.  First, only the size of the data was required to
  374.    keep the data, and second, the next piece of data that you
  375.    store that is thirty bytes or less will be stored in the
  376.    vacated space.
  377.  
  378.    The thirty byte space that is available brings up an important
  379.    point.  We have run tests where one VLF file undergoes
  380.    millions of V_REPLACE()s.  The data ranged in random sizes
  381.    from one byte to ten thousand bytes.  The amount of vacant
  382.    space tended to level off at about 20% of the fully pack
  383.    file's size and at that point the VLF file stops growing,
  384.    period.
  385.  
  386.  
  387.  
  388.  
  389.    Disaster Recovery
  390.  
  391.    One of FlexFile's advantages is that it is very robust against common
  392.    disaster situations such as power loss.  Your DBV file may get damaged
  393.    during such a calamity, however, the damage done is local to the write
  394.    that was in progress when the interuption occurred.  That is, there is
  395.    no immediate ripple effect from a damaged section of a DBV to non
  396.    damaged sections.
  397.  
  398.    On the other hand, if your file gets damaged and you continue to use it,
  399.    you CAN cause more damage.  Therefore, you should prepare your code for
  400.    such an occurance (you can always rely on backups, but sometimes clients
  401.    simply fail to do their job of backing up regularly).
  402.  
  403.    If V_REPLACE() or V_DELETE() return a logical value (as opposed to a
  404.    character value) and/or V_ERROR() reports a 6200, 6500, 6700 or 9000
  405.    class of error, the DBV file may be corrupt.  (Syntax errors in calling
  406.    FlexFile functions can also cause these errors so check your syntax
  407.    first.)
  408.  
  409.    When you are certain that your syntax is not causing the problem, you
  410.    should rebuild the DBV file.  Rebuilding is a simple process and is
  411.    outlined by the following code.  The code is based on a DBF file called
  412.    "dbf_file.dbf" which has a six byte character field (a FlexFile
  413.    pointer-field) called <vlf>.  We then open the existing DBV and create a
  414.    new DBV into which to copy the old data.  Finally, we erase the old DBV
  415.    and rename the new one back to the old.
  416.  
  417.    Before any code such as this is implemented you should back up the files
  418.    involved.
  419.  
  420.  
  421.    // Open the controlling DBF and the DBV (with an alias of "OLD")
  422.    USE dbf_file
  423.    V_USE( "dbv_file", "old" )
  424.  
  425.    // Open a new DBV to recieve the copyable data (with an alias of "NEW").
  426.    V_SELECT(0)
  427.    V_USE( "tempdbv", "new" )
  428.  
  429.    DO WHILE !EOF()
  430.  
  431.       IF V_TYPE( dbf_file->vlf, "old" ) == 'U'
  432.          QOUT( "This record is damaged." )
  433.          WAIT
  434.          LOOP
  435.       ENDIF
  436.  
  437.       // If the type is Char, Num, Log, Date, array or FlexFile array
  438.       IF V_TYPE( dbf_file->vlf, "old" ) $ "CNLDAF"
  439.  
  440.          // Get the value from the DBV.
  441.          var = V_RETRIEVE( dbf_file->vlf, "old" )
  442.  
  443.          // Write the value to the new DBV.
  444.          dbf_file->vlf := V_REPLACE( var, space(6), "new" )
  445.  
  446.       ENDIF
  447.  
  448.       SKIP
  449.  
  450.    ENDDO
  451.  
  452.    FERASE( "dbv_file.dbv" )
  453.    FRENAME( "tempdbv.dbv", "dbv_file.dbv" )
  454.  
  455.  
  456.  
  457.    The other form of "disaster" that is fairly common is to loose a DBF
  458.    file that has pointer-fields into a DBV.  This is a very serious
  459.    situation because there is nothing in the DBV which points back into the
  460.    DBF.  However, there is a new function V_WALK_DBV() that allows the
  461.    programmer to step from field to field through the DBV file.  The steps
  462.    go from physical field to physical field and so the logical order of the
  463.    file is lost.  However, in extreme situations this function may be
  464.    helpful.  See V_WALK_DBV() for more information.
  465.  
  466.  
  467.  
  468.  
  469.               Saving and Retrieving Clipper's arrays
  470.  
  471.  
  472.    Saving and retrieving Clipper S'87 arrays
  473.  
  474.    To save a an array using the S'87 version of the library
  475.    (Flex_S87.lib), you treat the array like any other variable.
  476.    For example,
  477.  
  478.        && Declare an array
  479.        DECLARE arr[100]
  480.  
  481.        && Put some junk in it.
  482.        afill( arr, "Solid waste" )
  483.  
  484.        && Save the array (assume a DBF and DBV are open).
  485.        REPLACE vlf WITH V_REPLACE( arr, vlf )
  486.  
  487.    To retrieve that same array in S'87 takes more than one line of code.
  488.    Remember that V_LEN() returns the total number of elements in
  489.    a S'87 array.
  490.  
  491.        && Assume that we are still on the same record in
  492.        && the DBF but we do not already have a declared array.
  493.        && First we need to DECLARE the array to be the size of
  494.        && the array we stored above.
  495.        DECLARE newarr[ V_LEN(vlf) ]
  496.  
  497.        && Now we fill the array.
  498.        V_FILLARR( newarr, vlf )
  499.  
  500.    Although that was slightly awkward that is all there is to it.
  501.  
  502.  
  503.    Saving and retrieving Clipper 5.0 arrays
  504.  
  505.    To save an array with the Clipper 5.0 library (FlexFile.lib)
  506.    you treat the array like you would any other Clipper variable.
  507.  
  508.       // Save the original array
  509.       REPLACE vlf WITH V_REPLACE( arr, vlf )
  510.  
  511.       // Retrieve it later
  512.       newarr = V_RETRIEVE( vlf )
  513.  
  514.  
  515.  
  516.    Indexing on Variable Length Fields
  517.  
  518.    There are several issues that must be addressed by the programmer in
  519.    order to create and maintain an index on part (or all) of a FlexFile
  520.    Variable Length Field.
  521.  
  522.    First, creating an index is as easy as:
  523.  
  524.       INDEX ON V_RET( vlf_fld, "ALIAS_1", 1, 15 ) TO NTX_FILE.NTX
  525.  
  526.    This would create an index on the first fifteen characters of a FlexFile
  527.    VLF. However, every element of a clipper index must be the same length
  528.    and the above example does not guarantee this.  (If V_RETRIEVE() returns
  529.    a string of less than 15 characters, you will corrupt your index.)  So,
  530.    you should PAD() the return from V_RETRIEVE() with spaces as in:
  531.  
  532.       INDEX ON PAD( V_RET(.....), 15 ) TO NTX_FILE.NTX
  533.  
  534.    The second issue is to note that only data of the same type can be
  535.    indexed in this manner.  Accordingly, make sure that the character data
  536.    is not binary data.  If a CHR(0) is found in the first 15 characters of
  537.    the above example, Clipper will consider that to indicate the end of the
  538.    string.  This will make the string's length different from other strings
  539.    in the index and, thereby, corrupt the index.
  540.  
  541.    The last issue is described below, but is more complex. However, it is
  542.    not necessary to understand why, as long as you always abide by the
  543.    rule:  You must always have a REPLACE command that does not have a
  544.    V_REPLACE in its syntax before REPLACEs that contain V_REPLACE(). For
  545.    example,
  546.  
  547.       && INCORRECT....will corrupt the index if the index relys on either
  548.       && the data pointed to by vlf_1 or vlf_2.
  549.       REPLACE vlf_1 WITH V_REPLACE( "testing", vlf_1 )
  550.       REPLACE vlf_2 WITH V_REPLACE( "testing", vlf_2 )
  551.       SKIP
  552.  
  553.       && CORRECT....the first replace is a "dummy" but maintains integrity.
  554.       REPLACE any_fld WITH any_fld
  555.       REPLACE vlf_1 WITH V_REPLACE( "testing", vlf_1 )
  556.       REPLACE vlf_2 WITH V_REPLACE( "testing", vlf_2 )
  557.       SKIP
  558.  
  559.    First, the only reason I placed two V_REPLACE()s in the example is to
  560.    show that only one "dummy" replace is necessary before any number of
  561.    imbedded V_REPLACE()s.  Remember that anything that causes the index to
  562.    be updated (such as COMMIT, SKIP, SEEK, etc.) require that a new "dummy"
  563.    replace be used before attempting another REPLACE with imbedded
  564.    V_REPLACE()s.  For example,
  565.  
  566.       && CORRECT
  567.       REPLACE any_fld WITH any_fld
  568.       REPLACE vlf_1 WITH V_REPLACE( "testing", vlf_1 )
  569.       REPLACE vlf_2 WITH V_REPLACE( "testing", vlf_2 )
  570.       SKIP
  571.  
  572.       && INCORRECT....will corrupt the index without another "dummy"
  573.       && replace after the COMMIT.  Assuming, of course, that vlf_2
  574.       && is included in the index key.
  575.       REPLACE any_fld WITH any_fld
  576.       REPLACE vlf_1 WITH V_REPLACE( "testing", vlf_1 )
  577.       COMMIT
  578.       REPLACE vlf_2 WITH V_REPLACE( "testing", vlf_2 )
  579.  
  580.  
  581.    Ok, so what is going on?  Understanding the sequence of events that
  582.    occurs during a REPLACE is critical to understanding the apparent
  583.    paradox in the examples above.
  584.  
  585.    Remembering that the arguments of a function or command are all
  586.    evaluated before the function itself is called, the syntax
  587.  
  588.       REPLACE vlf_fld WITH V_REP( "Testing an indexed replace", vlf_fld )
  589.    
  590.    first executes FlexFile's V_REPLACE() and then executes Clipper's
  591.    REPLACE.
  592.  
  593.    This affects indexing because Clipper always evaluates the index key
  594.    twice.  Once at the begining of the first of one or more REPLACEs (to
  595.    remember which index key has to be removed from the index) and the
  596.    second after any of several "commit" commands such as COMMIT, SKIP,
  597.    SEEK, GOTO, etc. (to calculate and insert a new index key).  However, if
  598.    FlexFile already deleted the old information pointed to by vlf_fld
  599.    before CLIPPER began to execute the REPLACE code, then the first
  600.    evaluation of the index key occurs after its data has already been
  601.    deleted by FlexFile.
  602.  
  603.    I realize this is confusing so I will try again in steps:
  604.  
  605.                                        ┌─ step 2  ┌─ step 1
  606.                                        │          │
  607.       REPLACE vlf_fld WITH V_REPLACE( "testing", vlf_fld )
  608.       │                    │
  609.       └─ step 4            └─ step 3
  610.          step 5
  611.  
  612.    1. FlexFile deletes the data associated with the pointer-field vlf_fld
  613.    that is in the file before the REPLACE.
  614.  
  615.    2. FlexFile puts away the text "testing" in an appropriate location.
  616.  
  617.    3. FlexFile returns a six byte pointer-field which is immediately passed
  618.    to REPLACE.  This pointer-field is different than that of step 1 and
  619.    this new pointer-field is not yet in the file (it is being stored in
  620.    memory for the moment).
  621.  
  622.    4. Clipper begins executing its REPLACE code with the string passed to
  623.    it from step 3.
  624.  
  625.    5. Clipper evaluates the index and stores the evaluated value in a
  626.    buffer.  This sets up the error.  The index key should evaluate to the
  627.    data pointed to by the vlf_fld which is still in the file. However,
  628.    FlexFile deleted that data in step 1. Therefore, the V_RETRIEVE() in the
  629.    index key will return a null string and your PAD function will change
  630.    this to 15 bytes of spaces.
  631.  
  632.    No Clipper error actually occurs until the first COMMIT, SKIP, SEEK,
  633.    etc.  It is at this point that Clipper does the work on the index.  The
  634.    first thing Clipper does is delete the old index key (which was put into
  635.    a memory buffer in step 5).  However, Clipper will not be able to find
  636.    an index key which matches the 15 spaces in the memory buffer and,
  637.    therefore, assumes that the index is corrupted.
  638.  
  639.    So, the way to resolve this is to have a "dummy" replace that will force
  640.    Clipper to evaluate the index key BEFORE FlexFile deletes the key.  The
  641.    thing that may be confusing is that Clipper does not care which field is
  642.    in the first REPLACE.  It is simply a fact that the first REPLACE
  643.    evaluates the "before" index key regardless of whether the REPLACE even
  644.    affects the index key.  It is also a fact that no other index action
  645.    occurs until a "commit" type command.  At that point the "before" key is
  646.    deleted from the index and the "after" key is inserted into the index.
  647.  
  648.  
  649.  
  650.  
  651.    FlexFile Networking
  652.  
  653.    FlexFile typically requires no special network considerations
  654.    beyond Clipper's RLOCK() and FLOCK().  That is to say, if you
  655.    acquire an RLOCK() on a record in a DBF file that has a
  656.    pointer-field, no other user will have write access to that
  657.    record.  Because Clipper insists on an RLOCK() being acquired
  658.    before a REPLACE when a file is used non-exclusively, this
  659.    will suffice to protect the information to which the
  660.    pointer-field is related.
  661.  
  662.    FlexFile's internal tables lock and unlock automatically, and
  663.    require no programmer consideration.
  664.  
  665.    There is an additional network features which was incorporated
  666.    into FlexFile in order to aid the programmer in implementing
  667.    network compatible code.
  668.  
  669.    Every time a pointer is replaced with a new pointer, the new
  670.    pointer is guaranteed to have a different value even though it
  671.    may be pointing to the same position within the file.
  672.  
  673.    For example, if you have variable length data that is 30 bytes
  674.    long, residing at offset 5000 in the DBV file, and you replace
  675.    that data with new data that is also 30 bytes long, it is
  676.    highly probable that FlexFile will put the new data exactly
  677.    where the old data was (at offset 5000).  However, the
  678.    pointer-field that the V_REPLACE() function returns will be
  679.    different than the one that pointed to the data before the
  680.    REPLACE.
  681.  
  682.    This feature was implemented so that the programmer can assign
  683.    the pointer- field to a variable, then, without locking the
  684.    DBF record in which the pointer- field is located, modify the
  685.    pointer's data in memory.  Then when the user is ready to
  686.    replace the old data with the modified data, the programmer
  687.    can compare the pointer-field in memory with the DBF's
  688.    pointer-field in order to ascertain whether the data was
  689.    modified by another user while the current user was working on
  690.    the copy of it in memory.  For example:
  691.  
  692.        // Open the DBF and its related DBV
  693.        USE Shareit.dbf
  694.        IF V_USE( 'Shareit.dbv' ) == -1
  695.           ? "I could not open the Shareit.dbf file."
  696.           ? "I encountered error: " + STR( V_ERROR() )
  697.           QUIT
  698.        ENDIF
  699.  
  700.        // Save the pointer <vlf> to a variable
  701.        save_vlf = shareit->vlf
  702.  
  703.        // Retrieve the data from the DBV file into a memory var.
  704.        // The DBF lock is momentary.
  705.        DO WHILE !RLOCK()
  706.        ENDDO
  707.        memo_data = V_RETRIEVE( vlf )
  708.        UNLOCK
  709.  
  710.        // Edit the data.
  711.        memo_data = MEMOEDIT(memo_data...)
  712.  
  713.        // Lock the record and replace the data if the
  714.        // data has not been modified since the pointer was
  715.        // saved.  Again, the lock is momentary.
  716.        DO WHILE !RLOCK()
  717.        ENDDO
  718.  
  719.        IF save_vlf == shareit->vlf
  720.           REPLACE vlf WITH V_REPLACE( memo_data, vlf )
  721.        ELSE
  722.           ? "Data has been modified by another user!"
  723.           INKEY(0)
  724.        ENDIF
  725.        UNLOCK
  726.  
  727.    Although the Clipper locking technique shown is crude (at
  728.    best), the comparison of the saved version of the pointer with
  729.    the DBF pointer-field is a technique that many programmers
  730.    prefer.  The advantage is, of course, that you only need to
  731.    obtain two momentary locks rather than one long lock (during
  732.    which your user invariably goes on a lunch break).  The
  733.    disadvantage is that sometimes the user will have to retype an
  734.    entry.
  735.  
  736.    FlexFile's internal locking uses the DOS 3.x locking
  737.    mechanism.  Therefore, if you are using a lower version of DOS
  738.    or do not have SHARE.EXE loaded, FlexFile will ignore any
  739.    attempts to lock the file and proceed as if the lock was
  740.    successful.
  741.  
  742.  
  743.  
  744.  
  745.  
  746.    ARRAYS
  747.  
  748.    FlexFile supports an implementation of strongly typed
  749.    multi-dimensional arrays.  This array system is not to be
  750.    looked at as a replacement for the Clipper array system.
  751.    Clipper's array system is very powerful and it should not be
  752.    construed that FlexFile arrays will supersede the Clipper
  753.    system. Rather, FlexFile arrays should be used when the array
  754.    structure is regular, all the elements are of the same type,
  755.    and the array is very large.
  756.  
  757.    UNDER NO CIRCUMSTANCE SHOULD YOU USE FLEXFILE'S "S"TRING TYPE ARRAY IN
  758.    CLIPPER 5.0X.  EACH STRING ELEMENT OF THE ARRAY IS NOT HANDLED BY THE
  759.    VMM SYSTEM, AND, THEREFORE, THE CLIPPER COUNTERPART WILL TAKE LESS
  760.    MEMORY.  ALL OTHER FLEXFILE ARRAYS CAN BE SWAPPED, WHEN NECESSARY, BY
  761.    CLIPPER'S VMM SYSTEM.
  762.  
  763.    Why Use FlexFile Arrays
  764.  
  765.    FlexFile arrays are the only arrays to use if your array must
  766.    exceed Clipper's limit of 4029 elements.  For example, a
  767.    FlexFile array of logicals allows over 500,000 elements.  In
  768.    addition, each element of FlexFile array is at least six bytes
  769.    smaller than its Clipper counter part and at most thirteen
  770.    bytes and 7 bits smaller.  See Appendix B for a list of the
  771.    sizes of each type of FlexFile array.
  772.  
  773.    Clipper sees Flexfile arrays as regular variables.  Therefore,
  774.    you pass a Flexfile arrays by value (unless you
  775.    pass-by-reference using the @ symbol) and you can return a
  776.    FlexFile array as though it were a simple Clipper variable.
  777.    Because these arrays are typically large, it is best to pass
  778.    them by reference in order to avoid duplicating their content
  779.    in memory.
  780.  
  781.    The one exception to this is FlexFile's string type arrays.
  782.    These arrays pose a unique problem which is discuss below (See
  783.    FlexFile String Arrays).
  784.  
  785.  
  786.  
  787.  
  788.    Array indexes
  789.  
  790.    A "subscript" or an "index" refers to a particular element of
  791.    an array.  For example, Clipper refers to the third element of
  792.    a single dimensional array as ArrayName[3].  In this case, [3]
  793.    is a subscript of the array ArrayName.
  794.  
  795.    Subscripts may be passed using either of two different
  796.    methods.  Both methods are valid at any time.  The method to
  797.    use depends largely on whether your array is single or
  798.    multi-dimensional.
  799.  
  800.    If the array is a single dimensional array, then you define
  801.    and index position into that array exactly as you would
  802.    imagine.  For example, if you want to store 98.6 to the fifth
  803.    element of a single dimensional floating point type array, the
  804.    following line would be fine:
  805.  
  806.  
  807.        nTemperature = 98.6
  808.        nPatient = 5
  809.        A_STORE( aTemps, nTemperature, nPatient )
  810.  
  811.  
  812.    However, if the array is multi-dimensional it is necessary to
  813.    pass the index via the A_() function.  For example,  if you
  814.    want to store the temperature of the fifth patient on the
  815.    third day:
  816.  
  817.       A_STORE( aTemps, 98.6, A_( 5, 3 ) )
  818.  
  819.  
  820.    It is not wise to try to figure out the actual integer offset
  821.    of an element even though FlexFile would accept it; FlexFile
  822.    does this very fast on its own.  In addition, remember element
  823.    A_( 5, 3 ) is not the same element as A_(3, 5), and rarely, if
  824.    ever, will either array index refer to the fifteenth element
  825.    as it is laid out in memory.
  826.  
  827.  
  828.  
  829.  
  830.    Understanding FlexFile Arrays
  831.  
  832.    FlexFile arrays are similar to the arrays in languages such as
  833.    C or Pascal. The array is one block of memory (with the
  834.    exception of string arrays), and each element in the array
  835.    must be of the same type.
  836.  
  837.    There is an analogy relating multi-dimensional arrays to a set
  838.    of encyclopedias that helps in understanding and describing
  839.    their use.  This analogy is especially helpful in
  840.    understanding arrays that span into the fourth dimension.
  841.  
  842.    Imagine that you have a character array.  First, do not
  843.    confuse character arrays and string arrays.  A string array is
  844.    an array of pointers that point to strings of varying length
  845.    that reside in random positions in memory.  The string array
  846.    is actually an array of pointers and not an array of strings.
  847.    Each element points to a string of any length.
  848.  
  849.    A character array is a matrix of one byte storage locations
  850.    where each byte can hold one ASCII character.  In the analogy
  851.    of the encyclopedias, each letter is an element, a group of
  852.    letters that form words make up one row of text.  That one
  853.    line implies the first dimension.  Likewise, A group of lines
  854.    that makes up one page implies the second dimension, a group
  855.    of pages that makes up one volume implies the third dimension,
  856.    and all the volumes in the set of encyclopedias implies the
  857.    fourth dimensions.  We could continue the analogy into the
  858.    fifth dimension: a set of Britannica's next to The World Book
  859.    set implies a magnitude of two in the fifth dimension.
  860.  
  861.    You will often see, in the Array Function Reference chapter,
  862.    the concept of "wrapping".  For example, A_SCAN() will wrap at
  863.    the end of one line to the beginning of the next, and at the
  864.    end of one page it will wrap to the top of the next page.  All
  865.    functions that work with wrapping look at the array as it is
  866.    laid out in memory.
  867.  
  868.    It is important to dimension your arrays with this
  869.    understanding in mind:  the last dimension listed in the
  870.    declaration varies the smallest step in memory.  To declare
  871.    the array for an encyclopedia you would want to declare it as
  872.    follows:
  873.  
  874.        vols := 26
  875.        pages := 150
  876.        lines := 80
  877.        chars := 95
  878.        WorldBook = A_DECLARE( 'C', vols, pages, lines, chars )
  879.  
  880.    This declaration of a character array is actually illegal
  881.    because the array would exceed memory, however, it is
  882.    important to see how and why the dimensions are in the order
  883.    they are in.  The <chars> variable is last in order to insure
  884.    that each character is next to its proper neighbor in memory.
  885.    As far as A_STORE()ing and A_RETRIEVE()ing each character, the
  886.    layout makes little difference.  However, when you need to do
  887.    something like an A_FILL() (for a blank line), this layout
  888.    becomes critical.
  889.  
  890.    Lets say, for example, we want the fifth and sixth lines on
  891.    the fifteenth page of the fourth volume to be filled with
  892.    spaces.
  893.  
  894.       A_FILL( WorldBook, ' ', A_( 4, 15, 5, 1 ), 2 * lines )
  895.  
  896.  
  897.    This function fills the 160 characters following the specified
  898.    location.  Because the fill always begins at a point in memory
  899.    and moves to the next set of contiguous positions in memory,
  900.    it becomes critical how the array was declared.  For example,
  901.    if we switch the order of the <lines> and <chars> in the
  902.    declaration, and then perform the A_FILL(), the fill would put
  903.    one space on each line for 160 lines instead of one space for
  904.    each character for 160 characters.
  905.  
  906.    FlexFile String arrays (pointer arrays)
  907.  
  908.    Arrays of strings in FlexFile pose a peculiar problem.  When
  909.    the array is declared, FlexFile allocates memory for four
  910.    bytes per element.  These four bytes originally point to
  911.    nothing (null).  When you A_STORE() a string to an element,
  912.    however, new memory is allocated for the string.  This memory
  913.    does not reside within the array, but rather, at some random
  914.    location in memory. FlexFile knows where this is because it
  915.    stores a pointer in the array which points to the new data.
  916.  
  917.    A problem arises because the array itself is a Clipper
  918.    variable and has the scope of a Clipper variable.  If you
  919.    release this variable or allow it to fall out of scope,
  920.    Clipper does not know that it was pointing to your strings,
  921.    and so, Clipper releases the array of pointers without
  922.    releasing the strings that it points to.  In order to avoid
  923.    this, it is necessary to A_KILL() a string array before
  924.    allowing it to fall out of scope or be released.
  925.  
  926.  
  927.  
  928.  V_ALIAS()
  929.  Return the alias of the current or a specified DBV work area
  930. ───────────────────────────────────────────────────────────────────────────────
  931.  
  932.  Syntax
  933.  
  934.     V_ALIAS( [<nDBVArea>] )   ->    cDBVAlias
  935.  
  936.  Arguments
  937.  
  938.     <nDBVArea> is any valid DBV work area.
  939.  
  940.  Returns
  941.  
  942.     V_ALIAS() returns the alias of the DBV work area <nDBVArea>. If no
  943.     <nDBVArea> is specified, then the alias of the current work area
  944.     is returned.
  945.  
  946.  Description
  947.  
  948.     V_ALIAS() is used to return the name of a DBV work area. This name
  949.     is either the name of the DBV file or the name specified as the
  950.     second parameter in the V_USE() function. If there is no DBV file
  951.     open in the <nDBVArea>, V_ALIAS() will return a null string ("").
  952.  
  953.     Any function which accepts a DBV area as a parameter can also
  954.     accept an alias in place of the area.
  955.  
  956.     The alias is always returned in capital letters regardless of how
  957.     it was passed to V_USE().
  958.  
  959.  Notes
  960.  
  961.   ■ Do not confuse Clipper's alias names with FlexFile's; they are
  962.     mutually exclusive. For example, you can have a DBF file with an
  963.     alias of "MYFILE" and simultaneously have a DBV file with the same
  964.     alias.
  965.  
  966.  Examples
  967.  
  968.     // Open two DBV files in two new areas.
  969.     V_SELECT(1)
  970.     V_USE( "file1", "file_one" )// Creates if not existing
  971.     V_SELECT(2)
  972.     V_USE( "file2" )         // Creates if not existing
  973.  
  974.     ? V_ALIAS()              //  Returns: file2
  975.     ? V_ALIAS(1)             //  Returns: FILE_ONE
  976.  
  977.  
  978. See Also: V_SELECT() V_USE() V_FILES() V_FILE()
  979.  
  980.  
  981. ───────────────────────────────────────────────────────────────────────────────
  982.  V_BUFFERS()
  983.  Declare or retrieve the number of DBV file buffers
  984. ───────────────────────────────────────────────────────────────────────────────
  985.  
  986.  Syntax
  987.  
  988.     V_BUFFERS( [<nBuffers>] )    ->    nBuffers
  989.  
  990.  Arguments
  991.  
  992.     <nBuffers> is an integer value indicating a number of 1K buffers.
  993.     The default (which is also the minimum value) is 3 buffers.
  994.  
  995.  Returns
  996.  
  997.     V_BUFFERS() returns an integer indicating the previous setting of
  998.     the number of 1K buffers.
  999.  
  1000.  Description
  1001.  
  1002.     FlexFile manages all file input and output through a set of 1K
  1003.     buffers. Because there is such a diversity in buffered I/O from
  1004.     machine to machine, FlexFile offers the ability to customize the
  1005.     amount of space used for this purpose.
  1006.  
  1007.     If you are running with a disk cache or are tight on memory, leave
  1008.     the buffers at their default (and minimum) value of 3. If you have
  1009.     the space and would like to increase performance, increase the
  1010.     number of buffers.
  1011.  
  1012.  Notes
  1013.  
  1014.   ■ The buffers may only be changed when no DBV files are in use.
  1015.  
  1016.  Examples
  1017.  
  1018.     // Set FlexFile's buffers to 5K
  1019.     V_BUFFERS(5)
  1020.  
  1021.     V_USE( "file" )       // Open a file.
  1022.  
  1023.     // This line has no effect because files are open.
  1024.     V_BUFFERS(10)
  1025.  
  1026.     ? V_BUFFERS()         // Result: 5
  1027.  
  1028.  
  1029. See Also: V_FILES() V_USE()
  1030.  
  1031.  
  1032. ───────────────────────────────────────────────────────────────────────────────
  1033.  V_CLOSE()
  1034.  Close a DBV type file
  1035. ───────────────────────────────────────────────────────────────────────────────
  1036.  
  1037.  Syntax
  1038.  
  1039.     V_CLOSE( [<nWorkArea> | <cAlias>] )
  1040.  
  1041.  Arguments
  1042.  
  1043.     <nWorkArea> or <cAlias> is the DBV area or alias to close. If none
  1044.     is specified the file in the current DBV area is closed.
  1045.  
  1046.  Returns
  1047.  
  1048.     None.
  1049.  
  1050.  Description
  1051.  
  1052.     V_CLOSE() closes a FlexFile DBV type file. This is equivalent to
  1053.     V_USE() with no arguments.
  1054.  
  1055.  Notes
  1056.  
  1057.   ■ This function does not affect and is not affected by any
  1058.     Clipper data base functions or commands.
  1059.  
  1060.  Examples
  1061.  
  1062. // Open a DBV type file in FlexFile's area 1.
  1063. V_SELECT(1)
  1064. V_USE( "file" )
  1065.  
  1066. // Select a second area just for the heck of it.
  1067. V_SELECT(2)
  1068.  
  1069. // Close the file in area one.
  1070. V_CLOSE(1)
  1071.  
  1072. // Close a file (if one is open) in area 2
  1073. V_CLOSE()
  1074.  
  1075. See Also: V_USE() V_CLOSEALL()
  1076.  
  1077.  
  1078. ───────────────────────────────────────────────────────────────────────────────
  1079.  V_CLOSEALL()
  1080.  Close all open DBV type files
  1081. ───────────────────────────────────────────────────────────────────────────────
  1082.  
  1083.  Syntax
  1084.  
  1085.     V_CLOSEALL()
  1086.  
  1087.  Arguments
  1088.  
  1089.     None.
  1090.  
  1091.  Returns
  1092.  
  1093.     None.
  1094.  
  1095.  Description
  1096.  
  1097.     V_CLOSEALL() closes all open DBV type files in all open DBV work
  1098.     areas. In addition, the cache described by V_BUFFERS() and
  1099.     V_FILES() is released.
  1100.  
  1101.  Notes
  1102.  
  1103.   ■ This function does not affect and is not affected by any
  1104.     Clipper data base functions or commands.
  1105.  
  1106.  Examples
  1107.  
  1108. // Open a DBV type file in FlexFile's area 1.
  1109. V_SELECT(1)
  1110. V_USE( "file" )
  1111.  
  1112. // Open a second file in the next available area.
  1113. V_USE( "file2", , "NEW" )
  1114.  
  1115. // Close all open files.
  1116. V_CLOSEALL()
  1117.  
  1118. See Also: V_CLOSE() V_USE()
  1119.  
  1120.  
  1121. ───────────────────────────────────────────────────────────────────────────────
  1122.  V_COMMIT()
  1123.  Commit the DOS buffers to disk.
  1124. ───────────────────────────────────────────────────────────────────────────────
  1125.  
  1126.  Syntax
  1127.  
  1128.     V_COMMIT( [<nArea> | <cAlias>] )   ->   lSuccess
  1129.  
  1130.  Arguments
  1131.  
  1132.     <nArea> or <nAlias> is the DBV work area or alias whose buffers
  1133.     will be flushed.  Omitting this parameter causes all open DBV file
  1134.     buffers to be flushed.
  1135.  
  1136.  Returns
  1137.  
  1138.     V_COMMIT() returns a (.T.) on success.  Otherwise, it returns
  1139.     (.F.).
  1140.  
  1141.  Description
  1142.  
  1143.     DOS "buffers" disk I/O in order to speed up disk access.  The
  1144.     downside to this feature is that the data in the buffers can be
  1145.     lost if the machine "hangs" or is powered down before the buffers
  1146.     are copied to disk.  This problem was addressed in DOS version 3.3
  1147.     and later by allowing a call which forces DOS's buffers to be
  1148.     written to disk.  V_COMMIT() makes this call to DOS as described
  1149.     below.
  1150.  
  1151.     By default, FlexFile automatically commits all DOS buffers after
  1152.     every write operation. If you like this behavior, you should never
  1153.     need to call V_COMMIT().  This is the safest method but also the
  1154.     slowest.  In order to change this default behavior, the
  1155.     V_SET_COMMIT() function can be passed a logical (.T.) or (.F.) to
  1156.     turn on/off the automatic flushing feature. If automatic flushing
  1157.     is turned off, you must call V_COMMIT() explicitly in order to
  1158.     flush the DOS buffers as described below.
  1159.  
  1160.     If no parameter is passed, V_COMMIT() flushes all open DBV work
  1161.     areas to disk.
  1162.  
  1163.     If a numeric DBV work area or a character alias is passed,
  1164.     V_COMMIT() will flush the buffers associated with the work area
  1165.     specified.
  1166.  
  1167.         ┌──────────────────────── WARNING ─────────────────────────┐
  1168.         │ V_COMMIT and V_SET_COMMIT() are based on functions       │
  1169.         │ provided in DOS 3.3 and later.  Calls made to these      │
  1170.         │ functions on an earlier version of DOS will have no      │
  1171.         │ affect.                                                  │
  1172.         └──────────────────────────────────────────────────────────┘
  1173.  
  1174.  Example
  1175.  
  1176.     // Turn off automatic flushing in order to speed up operation.
  1177.     V_USE( "temp" )
  1178.     V_SET_COMMIT(.f.)
  1179.  
  1180.     DO WHILE !EOF()
  1181.        IF DELETED()
  1182.           REPLACE vlf_fld WITH V_DELETE( vlf_fld )
  1183.        ENDIF
  1184.        SKIP
  1185.     ENDDO
  1186.     PACK
  1187.  
  1188.     // Flush the buffers and turn automatic flushing back on.
  1189.     V_COMMIT()
  1190.     V_SET_COMMIT(.T.)
  1191.  
  1192.  
  1193. See also: V_SET_COMMIT() V_REPLACE() V_DELETE()
  1194.  
  1195.  
  1196.  
  1197. ───────────────────────────────────────────────────────────────────────────────
  1198.  V_DECRYPT()
  1199.  Decrypt a variable that has been encrypted with V_ENCRYPT()
  1200. ───────────────────────────────────────────────────────────────────────────────
  1201.  
  1202.  Syntax
  1203.  
  1204.     V_DECRYPT( <cEncrypted_string> )   ->    cOriginal
  1205.  
  1206.  Arguments
  1207.  
  1208.     <cEncrypted_string> is a variable previously encrypted with
  1209.     the V_ENCRYPT() function.
  1210.  
  1211.  Returns
  1212.  
  1213.     V_DECRYPT() returns a string as it was before a call to V_ENCRYPT().
  1214.  
  1215.  Description
  1216.  
  1217.     V_DECRYPT() will decrypt a string that has been previously encrypted
  1218.     with the V_ENCRYPT() function.  The string will only be decrypted
  1219.     properly if the V_SETKEY() function has been called with the same key
  1220.     that was in effect when the V_ENCRYPT() originally scrambled the
  1221.     <cEncrypted_string>.
  1222.  
  1223.  Examples
  1224.  
  1225.     LOCAL cSecure, cOriginal
  1226.  
  1227.     // Set the key to my dog's name.
  1228.     V_SETKEY( "Tally" )
  1229.  
  1230.     // Encrypt a character string.  Store the result in <cSecure>.
  1231.     cSecure = V_ENCRYPT( "Just try to decode <cSecure> without my dog." )
  1232.  
  1233.     // Later, decode the secured string with the help of my golden.
  1234.     // The call to V_SETKEY() is redundant because the program has not
  1235.     // terminated and it has not been set to a different V_SETKEY().
  1236.     V_SETKEY( "Tally" )
  1237.     cOriginal = V_DECRYPT( cSecure )
  1238.  
  1239.  
  1240. See Also: V_SETKEY() V_ENCRYPT()
  1241.  
  1242.  
  1243.  
  1244. ───────────────────────────────────────────────────────────────────────────────
  1245.  V_DELETE()
  1246.  Delete one field from a DBV file
  1247. ───────────────────────────────────────────────────────────────────────────────
  1248.  
  1249.  Syntax
  1250.  
  1251.     V_DELETE(    <cPointer>,
  1252.                  [<nArea> | <cAlias>] )    ->    cNull
  1253.  
  1254.  Arguments
  1255.  
  1256.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  1257.     memo-field).
  1258.  
  1259.     <nArea> or <nAlias> is the DBV work area or alias with which
  1260.     <cPointer> is related.
  1261.  
  1262.  Returns
  1263.  
  1264.     V_DELETE() returns a null string ("").
  1265.  
  1266.  Description
  1267.  
  1268.     V_DELETE() releases the space pointed to by <cPointer>. This space
  1269.     is then available for use by the next call to V_REPLACE() or any
  1270.     other function that requires DBV space. It is important to
  1271.     remember that there is no V_RECALL(). That is, once a DBV has been
  1272.     V_DELETE()d, that field is no longer recoverable.
  1273.  
  1274.     When you delete a record in a DBF file and you want to be able to
  1275.     recall that record (and its related VLF), do not use V_DELETE().
  1276.     Instead, just DELETE the record in the DBF. When you are ready to
  1277.     PACK the DBF, run a routine similar to the example below.
  1278.  
  1279.       ┌──────────────────────── WARNING ─────────────────────────┐
  1280.       │ V_DELETE() deletes the data associated with <cPointer>.  │
  1281.       │ Attempting to use <cPointer> after this function deletes │
  1282.       │ the data that it points to can corrupt the DBV file.     │
  1283.       └──────────────────────────────────────────────────────────┘
  1284.  
  1285.  Notes
  1286.  
  1287.   ■ V_DELETE() is permanent; there is no V_RECALL().
  1288.  
  1289.   ■ V_DELETE() is not necessary before a V_REPLACE(). The second
  1290.     parameter of V_REPLACE() is a pointer whose data space will be
  1291.     released before the REPLACE.
  1292.  
  1293.  Examples
  1294.  
  1295.     // Open a DBF and its related DBV
  1296.     USE dbf_file
  1297.     V_USE( "dbv_file" )
  1298.  
  1299.     // Store some data in the DBV and a pointer to the
  1300.     // data in a six byte pointer-field in the DBF
  1301.     REPLACE vlf WITH V_REPLACE( "This string is doomed", vlf )
  1302.  
  1303.     // Now delete that string.
  1304.     REPLACE vlf WITH V_DELETE( vlf )
  1305.  
  1306.     // Note: It is important to erase the pointer stored in
  1307.     //       vlf once its data has been deleted.  Because
  1308.     //       V_DELETE() returns a null string, REPLACEing <vlf> 
  1309.     //       guarantees that the pointer-field vlf will be
  1310.     //       destroyed.
  1311.  
  1312. See Also: V_REPLACE() V_STUFF()
  1313.  
  1314.  
  1315.  
  1316. ───────────────────────────────────────────────────────────────────────────────
  1317.  V_ENCRYPT()
  1318.  Encrypt a Clipper string variable
  1319. ───────────────────────────────────────────────────────────────────────────────
  1320.  
  1321.  Syntax
  1322.  
  1323.     V_ENCRYPT( <cString> )   ->    cGobbleTgook
  1324.  
  1325.  Arguments
  1326.  
  1327.     <cString> is any valid Clipper character string.
  1328.  
  1329.  Returns
  1330.  
  1331.     V_ENCRYPT() returns an ecrypted string with the same length as
  1332.     the original.
  1333.  
  1334.  Description
  1335.  
  1336.     V_ENCRYPT() encrypts a Clipper string based on the current key setting
  1337.     (see V_SETKEY()).  The string can later be V_DECRYPT()ed by using the
  1338.     same V_SETKEY() setting.
  1339.  
  1340.     V_ENCRYPT() encrypts a Clipper string so that it is not human readable.
  1341.     The encryption algorithm has not been designed to any particular
  1342.     specification, however, as the author of the algorithm, I would not
  1343.     want to be faced with the task of decrypting a string without the
  1344.     <key> with which it was encrypted (see V_SETKEY()).
  1345.  
  1346.  Examples
  1347.  
  1348.     LOCAL cSecure, cOriginal
  1349.  
  1350.     // Set the key to my dog's name.
  1351.     V_SETKEY( "Tally" )
  1352.  
  1353.     // Encrypt a character string.  Store the result in <cSecure>.
  1354.     cSecure = V_ENCRYPT( "Just try to decode <cSecure> without my dog." )
  1355.  
  1356.     // Later, decode the secured string with the help of my golden.
  1357.     // The call to V_SETKEY() is redundant because the program has not
  1358.     // terminated and it has not been set to a different V_SETKEY().
  1359.     V_SETKEY( "Tally" )
  1360.     cOriginal = V_DECRYPT( cSecure )
  1361.  
  1362.  
  1363. See Also: V_SETKEY() V_DECRYPT()
  1364.  
  1365.  
  1366.  
  1367. ───────────────────────────────────────────────────────────────────────────────
  1368.  V_ERROR()
  1369.  Report specific error codes from the DBV system
  1370. ───────────────────────────────────────────────────────────────────────────────
  1371.  
  1372.  Syntax
  1373.  
  1374.     V_ERROR()   ->    nErrorCode
  1375.  
  1376.  Arguments
  1377.  
  1378.     None.
  1379.  
  1380.  Returns
  1381.  
  1382.     V_ERROR() returns the FlexFile error code as a numeric integer.
  1383.  
  1384.  Description
  1385.  
  1386.     V_ERROR() is an error reporting function that will return the most
  1387.     recent error code that FlexFile set. If a failed operation has no
  1388.     FlexFile error code check the DOS error code by using Clipper's
  1389.     DOSERROR() function.
  1390.  
  1391.     For a complete list of error codes and their descriptions refer to
  1392.     Appendix B.
  1393.  
  1394.  Examples
  1395.  
  1396.     // Trying to V_REPLACE() data in an area that does not have a
  1397.     // file open causes an error.
  1398.     V_FILES(4)
  1399.     USE dbf_file       // Valid DBF file is opened.
  1400.     V_SELECT( 4 )      // No DBV file is open in area 4.
  1401.  
  1402.     // V_REPLACE() will return (.F.) because there is no file
  1403.     // open in area 4.  Because vlf is a six byte character
  1404.     // field, a runtime "data type mismatch" is produced.
  1405.     REPLACE vlf WITH V_REPLACE("Data type mismatch", vlf)
  1406.  
  1407.     //  In errorsys.prg...
  1408.     ? V_ERROR()     //  Returns 7301.
  1409.                     // Appendix B: DBV file not open.
  1410.  
  1411.  
  1412. See Also: errcodes.ngo:"Error Codes Introduction"
  1413.  
  1414.  
  1415.  
  1416. ───────────────────────────────────────────────────────────────────────────────
  1417.  V_EXCLUSIV()
  1418.  Establish exclusive or shared use of a DBV type file
  1419. ───────────────────────────────────────────────────────────────────────────────
  1420.  
  1421.  Syntax
  1422.  
  1423.     V_EXCLUSIV( <lToggle> )  ->    lSetting
  1424.  
  1425.  Arguments
  1426.  
  1427.     <lToggle> is a logical value. If <lToggle> is (.T.), then
  1428.     subsequent files opened with V_USE() will be opened exclusively.
  1429.  
  1430.     If <lToggle> is (.F.), then subsequent files opened with V_USE()
  1431.     will be opened in shared mode.
  1432.  
  1433.  Returns
  1434.  
  1435.     The current setting of V_EXCLUSIV().
  1436.  
  1437.  Description
  1438.  
  1439.     In a network environment, V_EXCLUSIV() determines whether the
  1440.     V_USE() function specified without the <lExclusive> parameter will
  1441.     be opened in shared or exclusive mode. If <lToggle> is (.T.) (the
  1442.     default), other users cannot V_USE() the same file until it has
  1443.     been closed.
  1444.  
  1445.     If <lToggle> is (.F.), all subsequent files opened by V_USE() without the
  1446.     <lExclusive> parameter will be opened in shared mode. Access by
  1447.     other users must be controlled programmatically. Typically, this
  1448.     can be done with Clipper's RLOCK() and FLOCK() functions. That is,
  1449.     if the pointer to a DBV is kept in a DBF file, then RLOCK()ing the
  1450.     record containing the pointer will prevent other users from
  1451.     accessing that field.
  1452.  
  1453.     Refer to Network Programming for more information.
  1454.  
  1455.  Notes
  1456.  
  1457.   ■ Error handling: Attempting to V_USE() a file which has been
  1458.     opened exclusively by another user causes V_USE() to return a -1.
  1459.     V_ERROR() will return an error code indicating this condition.
  1460.  
  1461.  Examples
  1462.  
  1463.     // Set up the environment so that all files are opened
  1464.     // in shared mode.
  1465.     #define EXCLUSIVE (.T.)
  1466.     V_EXCLUSIV( !EXCLUSIVE )
  1467.     
  1468.     // This file will be opened in shared mode.
  1469.     IF V_USE( "mainfile" ) == -1
  1470.        ? "Error: " + str( V_ERROR(), 4 )
  1471.        QUIT
  1472.     ENDIF
  1473.  
  1474.     // This V_USE() overrides the global V_EXCLUSIV() setting
  1475.     // and opens the file exclusively.
  1476.     V_USE( "tempfile", , "NEW", EXCLUSIVE )
  1477.  
  1478.     // Close all files.
  1479.     V_CLOSEALL()
  1480.  
  1481. See Also: V_USE() network.ngo:"Network Programming"
  1482.  
  1483.  
  1484.  
  1485. ───────────────────────────────────────────────────────────────────────────────
  1486.  V_FILE2VLF()
  1487.  Copy a DOS file into a VLF
  1488. ───────────────────────────────────────────────────────────────────────────────
  1489.  
  1490.  Syntax
  1491.  
  1492.     V_FILE2VLF(  <cFileName>,
  1493.                  <cOldPointer> )  ->     cNewPointer
  1494.  
  1495.  Arguments
  1496.  
  1497.     <cFileName> is the name of a disk file optionally including the
  1498.     path and drive designators.
  1499.  
  1500.     <cOldPointer> is a required six byte pointer-field or variable in
  1501.     which you have previously stored a pointer to variable length
  1502.     data. Passing six spaces causes FlexFile to assume that there is
  1503.     no old data to be released before the new <exp> data is saved.
  1504.  
  1505.  Returns
  1506.  
  1507.     V_FILE2VLF() returns a pointer which should be stored in the
  1508.     pointer- field with which the copied file is to be associated.
  1509.  
  1510.     V_FILE2VLF() returns (.F.) on error.  This causes the error system
  1511.     to be invoked with a "Data Type Mismatch".  Use V_ERROR() to fetch
  1512.     the specific error value (see Appendix B for a table of error
  1513.     descriptions).
  1514.  
  1515.     A typical error from this function is "File not found".  It is,
  1516.     therefore, the responsibility of the programmer to test for this
  1517.     condition before executing V_FILE2VLF().
  1518.  
  1519.  
  1520.  Description
  1521.  
  1522.     V_FILE2VLF() provides a mechanism for copying a DOS disk file into
  1523.     a VLF.  This is particularly handy in converting an application
  1524.     which has used Clipper's MEMOWRITE() function.
  1525.  
  1526.     V_FILE2VLF() is also handy for copying graphics images from disk
  1527.     files into a DBV file. When used in conjunction with V_VLF2FILE()
  1528.     a system can be implemented to handle graphics images which is
  1529.     compatible with the file based graphics systems such as DGE,
  1530.     SilverPaint, Flipper and the like.
  1531.  
  1532.     ┌────────────────────────── WARNING ──────────────────────────┐
  1533.     │ V_FILE2VLF() deletes the data associated with <cOldPointer> │
  1534.     │ before returning <cNewPointer>.  Attempting to use          │
  1535.     │ <cOldPointer> after this function deletes the data that it  │
  1536.     │ points to can corrupt the DBV file.                         │
  1537.     └─────────────────────────────────────────────────────────────┘
  1538.  
  1539.  Notes
  1540.  
  1541.   ■ No additional memory is required to copy a file into a VLF. It
  1542.     is, therefore, possible to import a file larger than 65K
  1543.     (Clipper's variable size limit).
  1544.  
  1545.   ■ V_TYPE() will return "C" (character) for any VLF that has been
  1546.     created by V_FILE2VLF(). This implies that V_RETRIEVE() will
  1547.     return a character string.
  1548.  
  1549.  Examples
  1550.  
  1551.     // Open a DBF file and its related DBV file
  1552.     // The dbf_file has a 12 byte field called "exe_name"
  1553.     // and the usual 6 byte field called "vlf"
  1554.     USE dbf_file
  1555.     ZAP
  1556.     INDEX ON exe_name TO dbf_file
  1557.     V_USE( "dbv_file" )
  1558.  
  1559.     // This may seem silly, but lets store the Clipper compiler
  1560.     // in the DBV file.
  1561.     APPEND BLANK
  1562.     REPLACE exe_name WITH "CLIPPER.EXE"
  1563.  
  1564.     // This will copy the Clipper.exe into a VLF.
  1565.     REPLACE vlf WITH V_FILE2VLF( exe_name, vlf )
  1566.  
  1567.     // Later when we want to execute Clipper (you better have
  1568.     // lots of memory).
  1569.     SEEK "CLIPPER.EXE"
  1570.     ? V_VLF2FILE( "TEMP.EXE",  vlf )
  1571.     ? V_ERROR()
  1572.  
  1573.     RUN temp
  1574.  
  1575.  
  1576. See Also: V_DBV2FILE() V_RETRIEVE()
  1577.  
  1578.  
  1579.  
  1580. ───────────────────────────────────────────────────────────────────────────────
  1581.  V_FILENAME()
  1582.  Return the file name of a file opened in a specified area
  1583. ───────────────────────────────────────────────────────────────────────────────
  1584.  
  1585.  Syntax
  1586.  
  1587.     V_FILENAME( [<nArea> | <cAlias>] )    ->    cFileName
  1588.  
  1589.  Arguments
  1590.  
  1591.     <nArea> or <cAlias> refers to the number or name of the target DBV
  1592.     work area.  If not specified, V_FILENAME() returns the file name
  1593.     from the currently selected DBV work area.
  1594.  
  1595.  Returns
  1596.  
  1597.     V_FILENAME() returns the DOS file name of the DBV file opened in
  1598.     the specified area.  If no file is open in the specified area,
  1599.     V_FILENAME() returns a null string ( "" ).
  1600.  
  1601.  Description
  1602.  
  1603.     V_FILENAME() is used to retrieve the DOS file name that refers to
  1604.     the DBV file. This name will not include the drive or path
  1605.     designators.
  1606.  
  1607.     This function is provided specifically for debugging where it is
  1608.     sometimes insufficient to only have access to the alias.
  1609.  
  1610.  Examples
  1611.  
  1612.     // Show the name of the file (not the alias)
  1613.     V_SELECT(1)
  1614.     V_USE( "pic_file.dbv", "pictures" )
  1615.  
  1616.     ? V_FILENAME()        //  Returns: PIC_FILE.DBV
  1617.     ? V_ALIAS()           //  Returns: PICTURES
  1618.     
  1619.     V_SELECT(2)
  1620.     ? V_FILENAME( "PICTURES" )//  Returns: PIC_FILE.DBV
  1621.     
  1622.     
  1623. See Also: V_ALIAS()
  1624.  
  1625.  
  1626.  
  1627. ───────────────────────────────────────────────────────────────────────────────
  1628.  V_FILES()
  1629.  Set the maximum number of DBV files to be in use concurrently
  1630. ───────────────────────────────────────────────────────────────────────────────
  1631.  
  1632.  Syntax
  1633.  
  1634.     V_FILES( [<nMaxFiles>] )    ->    nCurrentMax
  1635.  
  1636.  Arguments
  1637.  
  1638.     <nMaxFiles> is the maximum number of DBV type files that can be in
  1639.     V_USE() concurrently. If none is specified, V_FILES() will simply
  1640.     return the current setting.
  1641.  
  1642.  Returns
  1643.  
  1644.     V_FILES() returns the current setting of the maximum file count.
  1645.  
  1646.  Description
  1647.  
  1648.     V_FILES() offers the programmer the opportunity to set the maximum
  1649.     number of files that the program will have in use at any one time.
  1650.     This feature allows FlexFile to keep the memory used for the file
  1651.     headers in a contiguous block which avoids memory fragmentation.
  1652.  
  1653.     Each file requires 84 bytes for the header information. Therefore,
  1654.     multiply the <nMaxFiles> by 84 in order to calculate the total
  1655.     memory requirement for the files opened in your system.
  1656.  
  1657.  Notes
  1658.  
  1659.   ■ The maximum number of files cannot be changed unless all DBV files are
  1660.     closed.
  1661.  
  1662.   ■ This function is independent of the V_BUFFERS() setting.
  1663.  
  1664.  Examples
  1665.  
  1666.     // Set FlexFile's maximum file count to 2 files
  1667.     V_FILES(2)
  1668.  
  1669.     V_USE( "file1" )         // Open first file.
  1670.     V_USE( "file2", ,"NEW" ) // Open second file
  1671.                              // in a new area.
  1672.  
  1673.     // Attempt to open a third file in a new area fails.
  1674.     IF V_USE( "file3", ,"NEW" ) == -1
  1675.        ? "Too many files in use."
  1676.        ? V_ERROR()        // Result: 8001
  1677.     ENDIF
  1678.  
  1679.     // This line has no effect because files are open.
  1680.     V_FILES(5)
  1681.  
  1682.     ? V_FILES()           // Result: 2
  1683.  
  1684.  
  1685. See Also: V_BUFFERS() V_USE()
  1686.  
  1687.  
  1688.  
  1689. ───────────────────────────────────────────────────────────────────────────────
  1690.  V_FILLARR()
  1691.  Fill a Clipper S87 array with contents stored to a DBV file
  1692. ───────────────────────────────────────────────────────────────────────────────
  1693.  
  1694.  Syntax
  1695.  
  1696.     V_FILLARR(   <aTarget>,
  1697.                  <cPointer>,
  1698.                  [<nArea> | <cAlias>] )
  1699.  
  1700.  Arguments
  1701.  
  1702.     <aTarget> is the Clipper S87 array to be filled.
  1703.  
  1704.     <cPointer> is a six byte pointer-field that points to the DBV
  1705.     containing a Clipper type array.
  1706.  
  1707.     <cAlias> or <nArea> is a DBV file alias or area specified when the
  1708.     file was V_USE()d. If omitted, the pointer will point into the
  1709.     currently selected DBV area.
  1710.  
  1711.  Returns
  1712.  
  1713.     None.  However, <aTarget> is modified.
  1714.  
  1715.  Description
  1716.  
  1717.     V_FILLARR() is used to fill an array when using the Clipper S87
  1718.     compiler (See V_RETRIEVE() for retrieving an array in an application
  1719.     compiled with Clipper 5.0). The <aTarget> array must exist and will be
  1720.     filled until <aTarget> has no remaining elements or the array pointed
  1721.     to by <cPointer> has no more elements (which ever limit is reached
  1722.     first).
  1723.  
  1724.     Use the V_LEN() function to dimension the array immediately before
  1725.     V_FILLARR() (see examples below).
  1726.  
  1727.     The ability to save Clipper arrays is one of the most powerful
  1728.     features of FlexFile. Essentially, it simulates Variable Length
  1729.     Records as well as creating a three dimensional effect in your
  1730.     data base files.
  1731.  
  1732.     For example, picture a student master DBF file with the fields
  1733.     LastName, FirstName, Addr, Major, and Minor. If you decide to
  1734.     expand the file and include the sports, clubs and associations
  1735.     that the student is involved in, you have two choices. You can
  1736.     create a new related file (with a new index), or you can insert
  1737.     several new fields in the master DBF for each category, limiting
  1738.     the entries possible in any one category and wasting space on
  1739.     students who do not have entries in one or more of the categories.
  1740.  
  1741.     With FlexFile, however, you can add just one field in the master
  1742.     file and save an array of any length to this field. Not only do
  1743.     you eliminate a file, its index, and its relation, but also, one
  1744.     function call can load arrays with the new data eliminating the
  1745.     need to code "scatter" and "gather" routines.
  1746.  
  1747.  Notes
  1748.  
  1749.   ■ It is not necessary to use this routine to retrieve a FlexFile
  1750.     type array.
  1751.  
  1752.  Examples
  1753.  
  1754.     && S'87 compiler only. See V_RETRIEVE() for Clipper 5.0
  1755.  
  1756.     && Open a DBF and a related DBV file
  1757.     USE dbf_file
  1758.     V_USE( "dbv_file" )
  1759.  
  1760.     DECLARE aNames[3]
  1761.     aNames[1] = "Tania"
  1762.     aNames[2] = "Mary"
  1763.     aNames[3] = "Allison"
  1764.  
  1765.     && Store the array to the DBV file and its pointer to the DBF
  1766.     REPLACE vlf WITH V_REPLACE( aNames, vlf )
  1767.  
  1768.     && Declare the new array to the proper size.
  1769.     DECLARE aNewNames[ V_LEN( vlf ) ]
  1770.  
  1771.     && Fill the array with the data.
  1772.     V_FILLARR( aNewNames, vlf )
  1773.  
  1774.     && Show that it worked
  1775.     ? aNewNames[1]        && Result: Tania
  1776.  
  1777.  
  1778.  
  1779. See Also: V_REPLACE() V_RETRIEVE() V_LEN()
  1780.  
  1781.  
  1782. ───────────────────────────────────────────────────────────────────────────────
  1783.  V_GETWNDRC()
  1784.  Return the rows or columns from a Proclip window stored in a DBV file
  1785. ───────────────────────────────────────────────────────────────────────────────
  1786.  
  1787.  Syntax
  1788.  
  1789.     V_GETWNDRC( <cPointer>, <cRowOrCol> )    ->    nValue
  1790.  
  1791.  Arguments
  1792.  
  1793.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  1794.     memo-field).
  1795.  
  1796.     <cRowOrCol> is either an 'R' or a 'C' (non case sensitive)
  1797.     requesting the row or column respectively.
  1798.  
  1799.  Returns
  1800.  
  1801.     V_GETWNDRC() returns the rows or columns of a Proclip window in a
  1802.     DBV file much like Proclip's WNDVROWS() and WNDVCOLS() would.
  1803.  
  1804.  Description
  1805.  
  1806.     V_GETWNDRC() is used to query a Proclip window that has been saved
  1807.     to a DBV. The rows and columns are the virtual rows and columns
  1808.     and not the rows and columns of a viewport that may have been
  1809.     active when the window was V_REPLACE()d.
  1810.  
  1811.  
  1812.  Examples
  1813.  
  1814.     // Create a proclip window
  1815.     pc_handle = WNDCREATE( 5, 10 )
  1816.  
  1817.     // Save the window to a DBV file
  1818.     REPLACE vlf WITH V_REPLACE( pc_handle, , , 'P' )
  1819.  
  1820.     // Show the rows and columns of the window.
  1821.     ? V_GETWNDRC( vlf, 'R' ) // Result: 5
  1822.     ? V_GETWNDRC( vlf, 'C' ) // Result: 10
  1823.  
  1824.  
  1825. See Also: V_REPLACE() V_TYPE()
  1826.  
  1827. ───────────────────────────────────────────────────────────────────────────────
  1828.  V_HANDLE()
  1829.  Return the DOS file handle for a DBV file.
  1830. ───────────────────────────────────────────────────────────────────────────────
  1831.  
  1832.  Syntax
  1833.  
  1834.     V_HANDLE( [<nArea> | <cAlias>] )      ->   nHandle
  1835.  
  1836.  Arguments
  1837.  
  1838.     <nArea> or <cAlias> refers to the number or name of the target DBV
  1839.     work area. If not specified, the current DBV work area is assumed.
  1840.  
  1841.  Returns
  1842.  
  1843.     V_HANDLE() returns a numeric integer whose value is the DOS file handle
  1844.     for the specified DBV work area.
  1845.  
  1846.  Description
  1847.  
  1848.     V_HANDLE() can be used in conjunction with Clipper's Fxxxx() class of
  1849.     low level file functions.  Great care must be taken when using FWRITE()
  1850.     to assure that the bounds of the VLF are not overwritten.  It is far
  1851.     safer and usually sufficient to use V_RETRIEVE() and V_POKE() to manage
  1852.     low level access to a VLF.
  1853.  
  1854.       ┌───────────────────────── WARNING ───────────────────────────┐
  1855.       │ Extreme care must be taken when using FWRITE() on a DBV     │
  1856.       │ type file.  Overwriting the bounds of a VLF by one byte can │
  1857.       │ corrupt the entire file.                                    │
  1858.       └─────────────────────────────────────────────────────────────┘
  1859.  
  1860.  
  1861.  Examples
  1862.  
  1863.     #include "fileio.ch"
  1864.     LOCAL buffer
  1865.  
  1866.     // Open a DBF file and its related DBV file
  1867.     USE dbf_file
  1868.     V_USE( "dbv_file" )
  1869.  
  1870.     FSEEK( V_HANDLE(), V_PTR( vlf_fld ), FS_SET )
  1871.  
  1872.     buffer = SPACE( V_LEN( vlf_fld ) )
  1873.     FREAD( V_HANDLE(), @buffer, LEN(BUFFER) )
  1874.  
  1875.     // The above code will fetch a VLF without file locking or
  1876.     // error checking just like the following one line of code:
  1877.     //         buffer = V_RETRIEVE( vlf_fld )
  1878.  
  1879.  
  1880. See Also: V_POKE() V_RETRIEVE() V_PTR() V_LEN()
  1881.  
  1882. ────────────────────────────────────────────────────────────────────────────────
  1883.  V_ISOPEN()
  1884.  Determine if a file is open in an area.
  1885. ────────────────────────────────────────────────────────────────────────────────
  1886.  
  1887.  Syntax
  1888.  
  1889.     V_ISOPEN( [<nArea> | <cAlias>] )      ->   lStatus
  1890.  
  1891.  Arguments
  1892.  
  1893.     <nArea> or <cAlias> refers to the number or name of the target DBV
  1894.     work area. If not specified, the current DBV work area is assumed.
  1895.  
  1896.  Returns
  1897.  
  1898.     V_ISOPEN() returns (.T.) if there is a file open in the current or
  1899.     specified DBV work area.  Otherwise, it returns (.F.).
  1900.  
  1901.     If a character alias is passed, V_ISOPEN() will return true if the
  1902.     alias is valid in any DBV work area.  If the character alias is
  1903.     not valid for any DBV work area, V_ISOPEN() will return (.F.).
  1904.  
  1905.  Description
  1906.  
  1907.     V_ISOPEN() tests the current or specified area returning a logical
  1908.     (.T.) if a file was found to be open in that area.  This function
  1909.     is important because the behavior of V_SELECT() does not allow
  1910.     this test as SELECT() does in Clipper (see V_SELECT()).
  1911.  
  1912.  Examples
  1913.  
  1914.     V_FILES(5)                    // Set maximum open files to five
  1915.     V_USE( "file1" )              // Open files in areas one and three.
  1916.     V_SELECT(3)
  1917.     V_USE( "file2" )
  1918.  
  1919.     FOR x = 1 TO 5
  1920.        ? V_ISOPEN(x), x           // Results: .T. for x=1 and x=3
  1921.     NEXT
  1922.  
  1923.     IF V_ISOPEN( "bogus" ) .OR. !V_ISOPEN( "file1" )
  1924.        ? "This is unreachable code."
  1925.     ELSE
  1926.        ? "Every thing went as expected!"
  1927.     ENDIF
  1928.  
  1929.  
  1930. See also: V_SELECT(), V_ALIAS(), V_USE()
  1931.  
  1932.  
  1933. ───────────────────────────────────────────────────────────────────────────────
  1934.  V_LEN()
  1935.  Return the length of data stored in a DBV
  1936. ───────────────────────────────────────────────────────────────────────────────
  1937.  
  1938.  Syntax
  1939.  
  1940.      V_LEN(  <cPointer>,
  1941.              <nArea> | <cAlias> )   ->   nCount
  1942.  
  1943.  Arguments
  1944.  
  1945.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  1946.     memo-field).
  1947.  
  1948.     <nArea> or <cAlias> refers to the number or name of the target DBV
  1949.     work area. If not specified, the current DBV work area is assumed.
  1950.  
  1951.  
  1952.  Returns
  1953.  
  1954.     V_LEN() returns the length of a character string or the number of
  1955.     elements in an array as a numeric integer.  V_LEN() returns only
  1956.     the number of elements in the first dimension of a Clipper 5.0
  1957.     array.
  1958.  
  1959.  Description
  1960.  
  1961.     With a character string, V_LEN() returns the number of bytes of
  1962.     the data associated with <cPointer>. This count will include any
  1963.     imbedded null bytes (CHR(0)).
  1964.  
  1965.     With an array, V_LEN() returns the number of elements in the first
  1966.     dimension of the array.
  1967.  
  1968.     For all other data types, V_LEN() returns 0.
  1969.  
  1970.  
  1971.  Examples
  1972.  
  1973.     // Declare and assign two local variables to be used.
  1974.     LOCAL cString, aNames := { "Sandra", "Beth", "Pirko" }
  1975.     cString = "This is a test"
  1976.  
  1977.     // Open a DBF file and its related DBV file
  1978.     USE dbf_file
  1979.     V_USE( "dbv_file" )
  1980.  
  1981.     // Store a string to record 1 and an array to record 2
  1982.     REPLACE vlf WITH V_REPLACE( cString, vlf )
  1983.     SKIP
  1984.     REPLACE vlf WITH V_REPLACE( aNames, vlf )
  1985.  
  1986.     GO TOP
  1987.     ? V_LEN( vlf )        // Result: 14
  1988.     SKIP
  1989.     ? V_LEN( vlf )        // Result: 3
  1990.     
  1991.  
  1992.  
  1993. See Also: V_TYPE() V_REPLACE() V_RETRIEVE() V_FILLARR()
  1994.  
  1995.  
  1996.  
  1997. ───────────────────────────────────────────────────────────────────────────────
  1998.  V_POKE()
  1999.  Write character data into a character type VLF
  2000. ───────────────────────────────────────────────────────────────────────────────
  2001.  
  2002.  Syntax
  2003.  
  2004.     V_POKE(  <cPointer>,
  2005.              <cData>,
  2006.              [<nOffset>] )
  2007.  
  2008.  Arguments
  2009.  
  2010.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  2011.     memo-field).
  2012.  
  2013.     <cData> is a character string to be written into the data pointed
  2014.     to by <cPointer>.  If the length of <cData> is greater than
  2015.     V_LEN(<cPointer>) - <nOffset>, the data will be trucated.
  2016.  
  2017.     <nOffset> is the offset within the data pointed to by <cPointer>
  2018.     at which to begin writing <cData>.  If not specified, <nOffset>
  2019.     defaults to 1.
  2020.  
  2021.  Returns
  2022.  
  2023.     None.
  2024.  
  2025.  Description
  2026.  
  2027.     V_POKE() is used when you want to overwrite some or all of a
  2028.     character type VLF.  V_POKE() is different than V_STUFF() in that
  2029.     it does not change or return <cPointer>.  Instead, V_POKE()
  2030.     modifies the data directly on the disk at its present location.
  2031.  
  2032.     V_POKE() is different than V_REPLACE() in that it cannot extend
  2033.     the length of the data pointed to by <cPointer> nor can it release
  2034.     any space associated with <cPointer>.
  2035.  
  2036.  Notes
  2037.  
  2038.   ■ V_POKE() is most useful when you know that the new data is the
  2039.     same length (or a subset) of the old data.
  2040.  
  2041.  Examples
  2042.  
  2043.     // Open a DBF and a related DBV file.
  2044.     USE Main.dbf
  2045.     V_USE( "Main.dbv" )
  2046.  
  2047.     // Replace can store any length data.
  2048.     APPEND BLANK
  2049.     REPLACE vlf_fld WITH V_REPLACE( "ABCDEFGH", vlf_fld )
  2050.  
  2051.     // Poke some data into the file.
  2052.     V_POKE( vlf_fld, "test", 3 )
  2053.     ? V_RETRIEVE( vlf_fld )// Result: ABtestGH
  2054.  
  2055.     // Try to write past the end of the fields current length.
  2056.     V_POKE( vlf_fld, "You cannot do much harm", 3 )
  2057.     ? V_RETRIEVE( vlf_fld )// Result: ABYou ca
  2058.  
  2059.  
  2060.  
  2061. See Also: V_REPLACE() V_STUFF()
  2062.  
  2063.  
  2064.  
  2065. ───────────────────────────────────────────────────────────────────────────────
  2066.  V_PTR()
  2067.  Return the absolute offset (file pointer) of data stored in a DBV file
  2068. ───────────────────────────────────────────────────────────────────────────────
  2069.  
  2070.  Syntax
  2071.  
  2072.     V_PTR( <cPointer> )   ->   nOffset
  2073.  
  2074.  Arguments
  2075.  
  2076.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  2077.     memo-field).
  2078.  
  2079.  Returns
  2080.  
  2081.     V_PTR() returns the absolute offset of data pointed to by
  2082.     <cPointer> in the DBV file associated with <cPointer>.
  2083.  
  2084.  Description
  2085.  
  2086.     For those who use Clipper's FOPEN() class of functions and who
  2087.     would like direct access to the data in a DBV type file, FlexFile
  2088.     provides V_PTR(). However, it is far safer to use V_RETRIEVE() and
  2089.     V_POKE().
  2090.  
  2091.     It must be noted that extreme care should be exercised when
  2092.     writing data into the DBV file. You should never write data that
  2093.     begins before V_PTR() or data which extends beyond V_LEN().
  2094.  
  2095.     ┌───────────────────────── WARNING ───────────────────────────┐
  2096.     │ Extreme care must be taken when using FWRITE() on a DBV     │
  2097.     │ type file.  Overwriting the bounds of a VLF by one byte can │
  2098.     │ corrupt the entire file.                                    │
  2099.     └─────────────────────────────────────────────────────────────┘
  2100.  
  2101.  
  2102.  Examples
  2103.  
  2104.     // Open a DBF file and its related DBV file.
  2105.     USE dbf_file
  2106.     V_USE( "dbv_file" )
  2107.  
  2108.     ? V_PTR( vlf )  // Result if the data related to vlf
  2109.                     // is 11,222 bytes from the beginning
  2110.                     // of dbv_file.dbv: 11222
  2111.  
  2112.  
  2113. See Also: V_RETRIEVE() V_POKE()
  2114.  
  2115.  
  2116.  
  2117. ───────────────────────────────────────────────────────────────────────────────
  2118.  V_REPLACE() / V_REP()
  2119.  Replace data stored in a DBV file with new data
  2120. ───────────────────────────────────────────────────────────────────────────────
  2121.  
  2122.  Syntax
  2123.  
  2124.     V_REPLACE(   <exp>,
  2125.                  <cOldPointer>,
  2126.                  [<cAlias> | <nArea>],
  2127.                  [<cDataType>])     ->      cNewPointer
  2128.  
  2129.  Arguments
  2130.  
  2131.     <exp> is any valid clipper variable including single or
  2132.     multi-dimensional arrays, FlexFile arrays, MemoEdit() strings,
  2133.     SaveScreen() strings, any binary data stored in a Clipper
  2134.     variable, as well as numerics, dates, and logicals, and Proclip
  2135.     windows.
  2136.  
  2137.     <cOldPointer> is a required six byte pointer-field or variable in
  2138.     which you have previously stored a pointer to variable length
  2139.     data. Passing six spaces causes FlexFile to assume that there is
  2140.     no old data to be released before the new <exp> data is saved.
  2141.     Refer to the discussion below for further explanation.
  2142.  
  2143.     <cAlias> or <nArea> is a DBV file alias or area specified with
  2144.     V_USE() or V_SELECT(). If omitted, the replace will occur in the
  2145.     current DBV area.
  2146.  
  2147.     <cDataType> is an expression which describes the data type of
  2148.     <exp>. FlexFile will assume Clipper's data type if this parameter
  2149.     is omitted. Only the first character of <cDataType> is significant
  2150.     (e.g. "C" is equivalent to "Character" ).
  2151.  
  2152.     This parameter is almost never necessary in this release of FlexFile.
  2153.     This is because the type of the data being saved is usually
  2154.     non-ambiguous. However, when saving either FlexFile's own strongly
  2155.     typed arrays or Proclip(tm) windows, it is necessary to tell FlexFile
  2156.     what you are saving.
  2157.  
  2158.     This is because FlexFile strongly typed arrays appear to Clipper as
  2159.     character data and Proclip window handles appear to Clipper as numeric
  2160.     values.  So, for example, if you save a Proclip window handle without
  2161.     providing this parameter, FlexFile will save the handle instead of
  2162.     the contents of the window.
  2163.  
  2164.  
  2165.     Table: V_REPLACE() data type codes
  2166.  
  2167.            ┌──────────────────────────────────────────────┐
  2168.            │ Character            Description             │
  2169.            ├──────────────────────────────────────────────┤
  2170.            │     C          Clipper character data        │
  2171.            │     N          Clipper numeric               │
  2172.            │     L          Clipper logical               │
  2173.            │     D          Clipper date                  │
  2174.            │     A          Clipper array                 │
  2175.            │     P          Proclip window handle         │
  2176.            │     F          FlexFile strongly typed array │
  2177.            └──────────────────────────────────────────────┘
  2178.  
  2179.  Returns
  2180.  
  2181.     V_REPLACE() returns a pointer which should be stored in the
  2182.     pointer- field with which the variable length data is to be
  2183.     associated.
  2184.  
  2185.     V_REPLACE() returns (.F.) on error.  This causes the error system
  2186.     to be invoked with a "Data Type Mismatch".  Use V_ERROR() to fetch
  2187.     the specific error value (see Appendix B for a table of error
  2188.     descriptions).
  2189.  
  2190.  Description
  2191.  
  2192.     V_REPLACE() stores the variable length data defined by <exp> and
  2193.     returns a six byte pointer <cNewPointer>. This pointer is the only
  2194.     way FlexFile will ever be able to access the <exp> data; if this
  2195.     pointer is lost the data in the DBV file will be inaccessible.
  2196.  
  2197.     It is highly recommended, therefore, that the V_REPLACE() function
  2198.     be imbedded in the same line of code as the Clipper REPLACE
  2199.     command (see examples below). <cNewPointer> will then be stored
  2200.     directly into a six byte pointer-field in the related DBF file.
  2201.  
  2202.     V_REPLACE() first deletes the data associated with <cOldPointer>
  2203.     freeing up the space, if any, that it was occupying. V_REPLACE()
  2204.     then looks for the smallest available space to put the <exp> new
  2205.     data. Finally, it returns <cNewPointer> to be used at any time by
  2206.     V_RETRIEVE(), V_REPLACE(), V_LEN(), etc. In most cases, you will
  2207.     be storing the <cNewPointer> in a DBF file (highly recommended).
  2208.  
  2209.     In designing the associated DBF structure, you will define a
  2210.     pseudo memo-field which will be a six byte (or more) character
  2211.     type field. FlexFile refers to these fields as pointer-fields.
  2212.     When a FlexFile pointer is stored in this field, the field will
  2213.     have six bytes of ASCII characters from the "irrational" range
  2214.     (128-255). This may appear as "garbage", but is actually a very
  2215.     compact encoded structure. It is encoded only to insure that nulls
  2216.     are never stored in your DBF file. After creating this field you
  2217.     can ignore it exactly as you would a DBT memo-field.  If you need
  2218.     to know the offset of the data in the DBV file use the function
  2219.     V_PTR().
  2220.  
  2221.     The V_REPLACE() function replaces data in the current DBV area or
  2222.     the <nArea>/<cAlias> area if specified. Attempting to use
  2223.     <cOldPointer> which points into one DBV file to delete/replace
  2224.     data in any other DBV file can be dangerous. Although there is a
  2225.     degree of protection against this kind of programmer error, it is
  2226.     possible that random data will be deleted from the target area
  2227.     corrupting that file.
  2228.  
  2229.  
  2230.     Incorrect: <fld1> is pointing to data in DBV area 1 but being used
  2231.     to refer to data in DBV area 2.
  2232.  
  2233.     V_SELECT(1)
  2234.     REPLACE fld1 WITH V_REPLACE( "No problem yet", fld1 )
  2235.           │
  2236.           └─────────────────────────────────────────────────┐
  2237.     V_SELECT(2)                                             │
  2238.     REPLACE fld1 WITH V_REPLACE( "File corruption possible", fld1)
  2239.  
  2240.  
  2241.     Correct: <fld1> is being used consistently in DBV area 1.
  2242.  
  2243.     V_SELECT(1)
  2244.     REPLACE fld1 WITH V_REPLACE( "Much better", fld1 )
  2245.           └──────────────────────────────┐
  2246.                                          │
  2247.     REPLACE fld1 WITH V_REPLACE( "Best", fld1 )
  2248.  
  2249.  
  2250.  
  2251.     ┌────────────────────────── WARNING ──────────────────────────┐
  2252.     │ V_REPLACE() deletes the data associated with <cOldPointer>  │
  2253.     │ before returning <cNewPointer>.  Attempting to use          │
  2254.     │ <cOldPointer> after this function deletes the data that it  │
  2255.     │ points to can corrupt the DBV file.                         │
  2256.     └─────────────────────────────────────────────────────────────┘
  2257.  
  2258.  Notes
  2259.  
  2260.   ■ All file sharing within the DBV file is handled automatically.
  2261.     It is the programmers responsibility to handle any one
  2262.     pointer-field exactly as you would any DBF field (i.e. use
  2263.     Clippers FLOCK()/RLOCK() functions). If a record is successfully
  2264.     locked with Clippers RLOCK() function, the pointer-field will be
  2265.     inaccessible to other users until the current task releases it.
  2266.  
  2267.   ■ If you use comparison of data in your networking code you are
  2268.     guaranteed that the pointer stored in the DBF field will be
  2269.     different after a replace even if the <cNewPointer> points to the
  2270.     same disk location as <cOldPointer>. It is, therefore, not
  2271.     necessary to compare the data itself (to see if it has been
  2272.     changed by one user while another user is working with it), but
  2273.     rather, it suffices to compare the pointers themselves.
  2274.  
  2275.  Examples
  2276.  
  2277.     // Example 1: exclusive
  2278.     // Assume the DBF file is indexed on the field scr_name
  2279.     // Assume the DBF file has a pointer-field scr_vlf.
  2280.     LOCAL cScr, aPickList
  2281.  
  2282.     // Open a DBF, an NTX and a related DBV file
  2283.     USE dbf_file INDEX dbf_file
  2284.     V_USE( "dbv_file" )
  2285.  
  2286.     // Save a screen segment to a variable.
  2287.     cScr = SAVESCREEN( 5, 5, 10, 50 )
  2288.  
  2289.     // Create array of Items on screen.
  2290.     aPickList = { "1. Add customer"       ,;
  2291.                   "2. Edit customer"      ,;
  2292.                   "3. Delete customer"    ,;
  2293.                   "4. Quit"                }
  2294.  
  2295.     // Make a name for the screen and append the screen and array to
  2296.     // the dbv_file.dbv.
  2297.     APPEND BLANK
  2298.     REPLACE scr_name WITH "main_menu"
  2299.     REPLACE scr_vlf  WITH V_REPLACE( cScr, scr_vlf )
  2300.     REPLACE picklist WITH V_REPLACE( aPickList, picklist )
  2301.  
  2302.     // Later or from a different application, restore
  2303.     // the screen segment and array.
  2304.     CLEAR
  2305.     SEEK "main_menu"
  2306.     RESTSCREEN( 5, 5, 10, 50, V_RETRIEVE( scr_vlf ) )
  2307.     aPickList = V_RETRIEVE( picklist )
  2308.  
  2309.  
  2310.     // Example 2: Network example
  2311.     // Assume the file has a pointer-field memo_vlf
  2312.     LOCAL ptr, cStr
  2313.  
  2314.     // Set exclusive off for Clipper and FlexFile.
  2315.     SET EXCLUSIVE OFF
  2316.     V_EXCLUSIV( .F. )
  2317.  
  2318.     // Open the files
  2319.     USE dbf_file INDEX dbf_file
  2320.     IF V_USE( "dbv_file" ) == -1
  2321.        ? "File not available at this time."
  2322.        QUIT
  2323.     ENDIF
  2324.  
  2325.     // Make up some data; append it to the files.
  2326.     APPEND BLANK
  2327.     WHILE NETERR()
  2328.        APPEND BLANK
  2329.     ENDDO
  2330.  
  2331.     // Lock the record an put some test data in the vlf.
  2332.     WHILE !RLOCK()
  2333.     ENDDO
  2334.     REPLACE dbf_file->memo_vlf WITH V_REPLACE( "Testing",
  2335.                              dbf_file->memo_vlf )
  2336.     UNLOCK
  2337.  
  2338.     // Remember the pointer for an "updated" test (see below).
  2339.     ptr = memo_vlf
  2340.  
  2341.     // Edit the existing data.  Note: the file is not locked.
  2342.     cStr = MEMOEDIT( V_RETRIEVE( memo_vlf ), 5, 5, 20, 50 )
  2343.  
  2344.     // Lock the record before the replace.
  2345.     WHILE !RLOCK()
  2346.     ENDDO
  2347.  
  2348.     // Test for an update between when we assigned memo_vlf to
  2349.     // ptr and now.
  2350.     IF ptr != dbf_file->memo_vlf
  2351.        ? "This memo field has been updated by another user."
  2352.        ? "It cannot be saved."
  2353.     ELSE
  2354.        REPLACE memo_vlf WITH V_REPLACE( cStr, memo_vlf )
  2355.     ENDIF
  2356.  
  2357.     UNLOCK
  2358.  
  2359.     // Close the files.
  2360.     USE
  2361.     V_USE()
  2362.  
  2363.  
  2364. See Also: V_USE() V_RETRIEVE() V_POKE()
  2365.  
  2366.  
  2367.  
  2368. ───────────────────────────────────────────────────────────────────────────────
  2369.  V_RETRIEVE() / V_RET()
  2370.  Return data that has been stored in a DBV file
  2371. ───────────────────────────────────────────────────────────────────────────────
  2372.  
  2373.  Syntax
  2374.  
  2375.     V_RETRIEVE(  <cPointer>,
  2376.                  [<nArea> | <cAlias>],
  2377.                  [<nStart>],
  2378.                  [<nCount>] )    ->    Data
  2379.  
  2380.  Arguments
  2381.  
  2382.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  2383.     memo-field).
  2384.  
  2385.     <nArea> or <cAlias> refers to the number or name of the target DBV
  2386.     work area. If not specified, the current DBV work area is assumed.
  2387.  
  2388.     <nStart> is the starting position in <cPointer>'s data. If
  2389.     <nStart> is positive, it counts from the beginning of the data
  2390.     pointed to by <cPointer>. If <nStart> is negative, it counts from
  2391.     the end of the data pointed to by <cPointer>.
  2392.  
  2393.     <nCount> is how many bytes of data to retrieve. If omitted,
  2394.     <nCount> begins at <nStart> and goes to the end of the data. If
  2395.     <nCount> is larger than the data, the excess is ignored.
  2396.  
  2397.  Returns
  2398.  
  2399.     V_RETRIEVE() will return the data pointed to by <cPointer>. On
  2400.     error, V_RETRIEVE() will return an empty value of the type stored
  2401.     or a logical (.F.) if no type can be determined. Use V_ERROR() to
  2402.     fetch the error code associated with a failed RETRIEVE().
  2403.  
  2404.  Description
  2405.  
  2406.     V_RETRIEVE() retrieves data stored in a DBV type file. The data
  2407.     retrieved will have the same type as the data that was stored
  2408.     during the V_REPLACE() (with the notable exception of Clipper
  2409.     arrays which are discussed below and Proclip windows which use the
  2410.     V_WNDCREAT() function).
  2411.  
  2412.  Notes
  2413.   ■ Clipper arrays stored using the V_REPLACE() function cannot be
  2414.     retrieved with V_RETRIEVE() when using the S87 compiler. Instead, use
  2415.     V_FILLARR() for Summer 87 type arrays.
  2416.  
  2417.   ■ <nStart> and <nCount> only apply to character data.  They will
  2418.     be ignored for any other data types.
  2419.  
  2420.  
  2421.  Examples
  2422.  
  2423.     // Open the DBF file and its associated DBV file
  2424.     #define CR_LF  ( CHR(13) + CHR(10) )
  2425.     LOCAL cStr
  2426.     USE dbf_file       // Has a 6 byte pointer-field: vlf.
  2427.     V_USE( "dbv_file" )// Is created if it does not exist.
  2428.  
  2429.     cStr ="And the silken, sad, uncertain,"+ CR_LF +;
  2430.           "rustling of each purple curtain,"+ CR_LF +;
  2431.           "thrilled me, filled me,"       + CR_LF +;
  2432.           "with fantastic terrors never felt before."
  2433.  
  2434.     // Store the string in DBV file and its pointer in
  2435.     // the DBF.
  2436.     APPEND BLANK
  2437.     REPLACE author WITH "Poe"
  2438.     REPLACE poem WITH "The Raven"
  2439.     REPLACE vlf WITH V_REPLACE( cStr, vlf )
  2440.  
  2441.     // Edit the string using V_RETRIEVE().
  2442.     cStr = MEMOEDIT( V_RETRIEVE( vlf ), 0, 0, 10, 45 )
  2443.  
  2444.     // Save the edited poem.
  2445.     REPLACE vlf WITH V_REPLACE( cStr, vlf )
  2446.  
  2447.  
  2448.  
  2449. See Also: V_FILLARR() V_REPLACE() V_STUFF() V_LEN()
  2450.  
  2451.  
  2452.  
  2453. ───────────────────────────────────────────────────────────────────────────────
  2454.  V_SELECT()
  2455.  Determine or select the DBV work area of a specified DBV alias
  2456. ───────────────────────────────────────────────────────────────────────────────
  2457.  
  2458.     V_SELECT( [<nNewArea>] | [<cAlias>] )      nOldArea
  2459.  
  2460.  Arguments
  2461.  
  2462.     <nNewArea> or <cAlias> is the new DBV area (or the new area associated
  2463.     with <cAlias>).
  2464.  
  2465.  Returns
  2466.  
  2467.     V_SELECT() returns the old area if the area is successfully
  2468.     changed or if no parameters are passed. On error (i.e. an area
  2469.     beyond the bounds of the V_FILES() setting), V_SELECT() will
  2470.     return a 0 and the DBV area will remain unchanged.
  2471.  
  2472.  Description
  2473.  
  2474.     V_SELECT() provides the functionality of a combination of
  2475.     Clipper's SELECT command and SELECT() function.  Specifically, it
  2476.     is used to change and/or fetch the active DBV work area.
  2477.  
  2478.     If no parameters are passed V_SELECT() parallels the Clipper
  2479.     SELECT() by returning the current DBV area. If, however, a valid
  2480.     DBV area or alias is passed, V_SELECT() will change the current
  2481.     DBV area as Clipper's SELECT command would and then returns the
  2482.     old DBV area as Clipper's SELECT() function would.  This
  2483.     functionality is slightly different than Clipper's SELECT() which
  2484.     returns the area of the alias but does not actually change the
  2485.     selected area.  If you need to test for the existance of an open
  2486.     file in a DBV work area, use the V_ISOPEN() function.
  2487.  
  2488.     V_SELECT() always returns a DBV area number regardless of whether
  2489.     the parameter passed was an alias or an area.
  2490.  
  2491.  Notes
  2492.  
  2493.   ■ Do not confuse Clipper's selected work area with FlexFile's;
  2494.     they are mutually exclusive. For example, you can have a DBF file
  2495.     open in area 2 and simultaneously have a DBV file open in
  2496.     V_SELECT() == 2. Likewise, SELECT <n> has no effect on the
  2497.     currently selected DBV area.
  2498.  
  2499.   ■ Remember that your maximum number of open files must be set by
  2500.     the V_FILES() function before V_USE()in your first DBV file. The
  2501.     valid DBV areas will then be from 1 to the value you passed to
  2502.     V_FILES(). See V_FILES() for more on defining the maximum number
  2503.     of work areas.
  2504.  
  2505.  Examples
  2506.  
  2507.     // Open three DBV files in three new areas.
  2508.     LOCAL nSelect
  2509.  
  2510.     nSelect = V_SELECT(1)    // Save current area and
  2511.                              // select area 1
  2512.     V_USE( "file1", "file_one" )// Creates if not existing
  2513.     V_SELECT(2)
  2514.     V_USE( "file2" )
  2515.     V_SELECT(0)              // Select the next area
  2516.     V_USE( "file3" )
  2517.     
  2518.     ? V_ALIAS()              //  Returns: FILE3
  2519.     ? V_ALIAS(1)             //  Returns: FILE_ONE
  2520.  
  2521.     V_SELECT( nSelect )      // Restore the first area.
  2522.  
  2523.  
  2524. See Also: V_ALIAS() V_USE() V_ISOPEN() V_FILES()
  2525.  
  2526.  
  2527. ───────────────────────────────────────────────────────────────────────────────
  2528.  V_SET_COMMIT()
  2529.  Set DOS buffer flushing automatically on/off
  2530. ───────────────────────────────────────────────────────────────────────────────
  2531.  Syntax
  2532.  
  2533.     V_SET_COMMIT( [<lToggle>] )   ->   lOldSetting
  2534.  
  2535.  Arguments
  2536.  
  2537.     <lToggle> is a logical expression which, if true, will turn on
  2538.     automatic buffer flushing.  If false,  it will turn off automatic
  2539.     buffer flushing.  If omitted, no change will be made and the
  2540.     function can be used simply to query the current setting.
  2541.  
  2542.  Returns
  2543.  
  2544.     V_SET_COMMIT() returns the old setting of the switch.
  2545.  
  2546.  Description
  2547.  
  2548.     DOS "buffers" disk I/O in order to speed up disk access.  The
  2549.     downside to this feature is that the data in the buffers can be
  2550.     lost if the machine "hangs" or is powered down before the buffers
  2551.     are copied to disk.  This problem was addressed in DOS version 3.3
  2552.     and later by allowing a call which forces DOS's buffers to be
  2553.     written to disk.  V_SET_COMMIT() sets DOS buffer flushing on
  2554.     automatic if a logical (.T.) is passed or turns off the automatic
  2555.     buffer flushing if a logical (.F.) is passed.  In the latter case,
  2556.     use V_COMMIT() to flush buffers manually.
  2557.  
  2558.         ┌──────────────────────── WARNING ─────────────────────────┐
  2559.         │ V_COMMIT and V_SET_COMMIT() are based on functions       │
  2560.         │ provided in DOS 3.3 and later.  Calls made to these      │
  2561.         │ functions on an earlier version of DOS will have no      │
  2562.         │ affect.                                                  │
  2563.         └──────────────────────────────────────────────────────────┘
  2564.  
  2565.  
  2566.  Example
  2567.  
  2568.     // Turn off automatic flushing in order to speed up operation.
  2569.     V_USE( "temp" )
  2570.     V_SET_COMMIT(.f.)
  2571.  
  2572.     DO WHILE !EOF()
  2573.        IF DELETED()
  2574.           REPLACE vlf_fld WITH V_DELETE( vlf_fld )
  2575.        ENDIF
  2576.        SKIP
  2577.     ENDDO
  2578.     PACK
  2579.  
  2580.     // Flush the buffers and turn automatic flushing back on.
  2581.     V_COMMIT()
  2582.     V_SET_COMMIT(.T.)
  2583.  
  2584.  
  2585. See also: V_COMMIT()
  2586.  
  2587.  
  2588. ───────────────────────────────────────────────────────────────────────────────
  2589.  V_SETKEY()
  2590.  Set a key or password for FlexFile encryption
  2591. ───────────────────────────────────────────────────────────────────────────────
  2592.  
  2593.  Syntax
  2594.  
  2595.     V_SETKEY( <cPassWord> )   ->    NIL
  2596.  
  2597.  Arguments
  2598.  
  2599.     <cPassWord> is any ten character string.  It must be at least one
  2600.     character and will be truncated to 10 if more characters are supplied.
  2601.  
  2602.  Returns
  2603.  
  2604.     NIL
  2605.  
  2606.  Description
  2607.  
  2608.     V_SETKEY() affects the return values of V_ENCRYPT() and V_DECRYPT().
  2609.     Essentially, <cPassWord> is a password that is used to encrypt a string
  2610.     and must be the same in order to decrypt the string.  Once set, the
  2611.     <cPassWord> is stored statically in memory.
  2612.  
  2613.     So, for example, you can set a password when your user starts a system
  2614.     (and enters his/her password) and use that password for the remainder
  2615.     of the session.  All strings V_ENCRYPT()ed with a particular
  2616.     <cPassWord> can only be V_DECRYPT()ed by using the same <cPassWord>.
  2617.  
  2618.  Examples
  2619.  
  2620.     LOCAL cSecure, cOriginal, cJunk
  2621.  
  2622.     // Set the key to my dog's name.
  2623.     V_SETKEY( "Tally" )
  2624.  
  2625.     // Encrypt a character string.  Store the result in <cSecure>.
  2626.     cSecure = V_ENCRYPT( "Just try to decode <cSecure> without my dog." )
  2627.  
  2628.     // Later, decode the secured string with the help of my golden.
  2629.     // Note that the <cPassWord> is being changed.
  2630.     V_SETKEY( "Junk" )
  2631.  
  2632.     // Because the <cPassWord> has been changed, the resulting string
  2633.     // will be unreadable.
  2634.     cJunk = V_DECRYPT( cSecure )
  2635.  
  2636.     // Now we change the <cPassWord> back to what was used during
  2637.     // the V_ENCRYPT()ion and the string will be properly restored.
  2638.     V_SETKEY( "Tally" )
  2639.     cOriginal = V_DECRYPT( cSecure )
  2640.  
  2641.  
  2642. See Also: V_ENCRYPT() V_DECRYPT()
  2643.  
  2644.  
  2645.  
  2646. ───────────────────────────────────────────────────────────────────────────────
  2647.  V_STUFF()
  2648.  Delete and insert new data into an existing VLF
  2649. ───────────────────────────────────────────────────────────────────────────────
  2650.  
  2651.  Syntax
  2652.  
  2653.     V_STUFF( <cOldPointer>,
  2654.              <nStart>,
  2655.              <nDelete>,
  2656.              <cNewString> )    ->    cNewPointer
  2657.  
  2658.  Arguments
  2659.  
  2660.     <cOldPointer> Is the pointer (usually stored in a DBF field),
  2661.     which points to the source string into which <cNewString> will be
  2662.     V_STUFF()ed.
  2663.  
  2664.     <nStart> is the starting position in the VLF where <cNewString>
  2665.     will be inserted.
  2666.  
  2667.     <nDelete> is the number of characters to delete from <cNewString>
  2668.     starting at <nStart>. Deletions are performed before insertions.
  2669.  
  2670.     <cNewString> is a string which will be inserted at the <nStart>
  2671.     position after the deletion of <nDelete> characters.
  2672.  
  2673.  Returns
  2674.  
  2675.     V_STUFF() returns a pointer which should be stored in the field
  2676.     with which the modified variable length data is to be associated.
  2677.  
  2678.     V_STUFF() returns (.F.) on error.  This causes the error system to
  2679.     be invoked with a "Data Type Mismatch".  Use V_ERROR() to fetch
  2680.     the specific error value (see Appendix B for a table of error
  2681.     descriptions).
  2682.  
  2683.  Description
  2684.  
  2685.     The V_STUFF() function works on VLFs much as Clipper's STUFF()
  2686.     works on strings. Working on VLFs, V_STUFF() will delete <nDelete>
  2687.     characters from the string pointed to by <cOldPointer> and then
  2688.     insert <cNewString> at the <nStart> position. V_STUFF() can,
  2689.     therefore, perform the following seven functions:
  2690.  
  2691.   ■ Insert: If <nDelete> is zero, V_STUFF() will not delete any
  2692.     characters before inserting <cNewString> at the <nStart> position.
  2693.     This effectively makes V_STUFF() an insert function.
  2694.  
  2695.   ■ Replace: If <nDelete> equals LEN( <cNewString> ), then
  2696.     V_STUFF() will effectively replace the data beginning at the
  2697.     <nStart> position. If the <cNewString> is always the same length
  2698.     as <nDelete> or if the comparison for equivalent length is easily
  2699.     tested, it is faster (less disk I/O) to use V_POKE().
  2700.  
  2701.   ■ Delete: If LEN( <cNewString> ) == 0 or <cNewString> is not
  2702.     passed, V_STUFF() will effectively delete <nDelete> characters
  2703.     beginning at the <nStart> position.
  2704.  
  2705.   ■ Replace and Insert: If <cNewString> is longer than <nDelete>,
  2706.     V_STUFF() will replace <nDelete> characters of the data pointed to
  2707.     by <cOldPointer> and insert the remaining length of <cNewString>.
  2708.  
  2709.   ■ Replace and Delete: If <cNewString> is shorter than <nDelete>,
  2710.     V_STUFF() will replace <nDelete> characters of the data pointed to
  2711.     by <cOldPointer> and then delete the remaining <nDelete>
  2712.     characters making the data shorter.
  2713.  
  2714.   ■ Replace and Delete rest: If <nDelete> is greater than or equal
  2715.     to the number of characters remaining after the <nStart> position
  2716.     of the data pointed to by <cOldPointer>, the old data is
  2717.     effectively trimmed at the <nStart> position before the
  2718.     <cNewString> is inserted.
  2719.  
  2720.   ■ Append: If <nStart> is equal to or greater than the length of
  2721.     the data pointed to by <cOldPointer>, the <nDelete> parameter is
  2722.     ignored and the <cNewString> data is appended to the end.
  2723.  
  2724.     ┌────────────────────────── WARNING ──────────────────────────┐
  2725.     │ V_STUFF() deletes the data associated with <cOldPointer>    │
  2726.     │ before returning <cNewPointer>.  Attempting to use          │
  2727.     │ <cOldPointer> after this function deletes the data that it  │
  2728.     │ points to can corrupt the DBV file.                         │
  2729.     └─────────────────────────────────────────────────────────────┘
  2730.  
  2731.  Notes
  2732.  
  2733.     The big advantage to V_STUFF() is that its operation is disk based
  2734.     rather than memory based. This is, however, a double edged sword.
  2735.     On the one hand, it offers the ability to create a VLF that is
  2736.     larger than 65K (Clipper's largest character string size). On the
  2737.     other hand, if you are not aware that <cNewPointer> points to data
  2738.     that is larger than 65K, you may be surprised when V_RETRIEVE() or
  2739.     similar functions trim their return value to 65K.  Although
  2740.     V_RETRIEVE() can only return a maximum length of 65K, it can pick
  2741.     up any portion of a longer string as long as the portion itself is
  2742.     no longer than 65K (see V_REPLACE()).
  2743.  
  2744.     In all cases, V_STUFF() will move the data pointed to by
  2745.     <cOldPointer> to a new location in the DBV file. It is, therefore,
  2746.     less disk intensive to use V_POKE() where possible. V_POKE() does
  2747.     not delete or insert, but simply overwrites data leaving it at the
  2748.     same disk location within the DBV file.
  2749.  
  2750.  Examples
  2751.  
  2752.     // Open a DBF file and its associated DBV file.
  2753.     USE dbf_file
  2754.     V_USE( "dbv_file" )
  2755.  
  2756.     // Put a string away.
  2757.     cStr = "ABCDEF"
  2758.     REPLACE vlf WITH V_REPLACE( cStr, vlf )
  2759.  
  2760.     // Insert.
  2761.     REPLACE vlf WITH V_STUFF( vlf, 2, 0, 'xyz' )
  2762.     ? V_RETRIEVE( vlf )      // Result: AxyzBCDEF
  2763.  
  2764.     // Replace.
  2765.     REPLACE vlf WITH V_STUFF( vlf, 2, 3, 'qrs' )
  2766.     ? V_RETRIEVE( vlf )      // Result: AqrsBCDEF
  2767.  
  2768.     // Delete.
  2769.     REPLACE vlf WITH V_STUFF( vlf, 2, 3, '' )
  2770.     ? V_RETRIEVE( vlf )      // Result: ABCDEF
  2771.  
  2772.     // Replace and Insert.
  2773.     REPLACE vlf WITH V_STUFF( vlf, 2, 2, 'xyz' )
  2774.     ? V_RETRIEVE( vlf )      // Result: AxyzDEF
  2775.  
  2776.     // Replace and delete.
  2777.     REPLACE vlf WITH V_STUFF( vlf, 2, 4, 'qrs' )
  2778.     ? V_RETRIEVE( vlf )      // Result: AqrsEF
  2779.  
  2780.     // Replace and delete rest.
  2781.     REPLACE vlf WITH V_STUFF( vlf, 2, 10, 'xyz' )
  2782.     ? V_RETRIEVE( vlf )      // Result: Axyz
  2783.  
  2784.     // Append.
  2785.     REPLACE vlf WITH V_STUFF( vlf, 10, 0, 'qrs' )
  2786.     ? V_RETRIEVE( vlf )      // Result: Axyzqrs
  2787.  
  2788. See Also: V_POKE() V_REPLACE() V_LEN() V_MEMOLINE()
  2789.  
  2790.  
  2791.  
  2792. ───────────────────────────────────────────────────────────────────────────────
  2793.  V_TIMEOUT()
  2794.  Advanced feature allows setting the internal lock timeout value
  2795. ───────────────────────────────────────────────────────────────────────────────
  2796.  
  2797.  Syntax
  2798.  
  2799.     V_TIMEOUT( [<nTimeOut>] )    ->    nOldSetting
  2800.  
  2801.  Arguments
  2802.  
  2803.     <nTimeOut> is the time interval (in seconds) before FlexFile will
  2804.     abort a function that is attempting an internal lock. The default
  2805.     value is forever.
  2806.  
  2807.  Returns
  2808.  
  2809.     V_TIMEOUT() returns the current timeout value.
  2810.  
  2811.  Description
  2812.  
  2813.     V_TIMEOUT() should not usually be necessary. If you are using
  2814.     Clipper's RLOCK() and FLOCK() functions to manage the DBF file,
  2815.     and you are keeping FlexFile's pointers in the DBF (this is the
  2816.     preferred method), then this function is not necessary.
  2817.  
  2818.     If you want FlexFile to timeout during an operation, then use this
  2819.     function to set the timeout value in seconds. Passing zero as
  2820.     <nTimeOut> will set the timeout value back to its default
  2821.     (forever).
  2822.  
  2823.     If you set the timeout to something other than zero, you must test
  2824.     the error code following a call to any of the FlexFile functions
  2825.     in the table below. The test is made by comparing V_ERROR() to
  2826.     zero or 5200. If the operation's lock timed out, V_ERROR() will
  2827.     return 5200, if the operation was successful, V_ERROR() will
  2828.     return zero. (See the example below.)
  2829.  
  2830.     Functions affected by V_TIMEOUT(): V_DELETE(), V_FILE2DBV(),
  2831.     V_REPLACE(), V_STUFF(), V_DBV2FILE()
  2832.  
  2833.  Examples
  2834.  
  2835.     // Setup defines and variables
  2836.     #define EXCLUSIVE_ (.T.)
  2837.     LOCAL error_no
  2838.  
  2839.     // Set the timeout to 3 seconds.
  2840.     V_TIMEOUT(3)
  2841.  
  2842.     // Open a DBF file and its related DBV file.
  2843.     USE dbf_file
  2844.     IF V_USE( "dbv_file", , , !EXCLUSIVE_ ) == -1
  2845.        error_no = V_ERROR()
  2846.        IF error_no == 5200
  2847.           ? "Attempt to lock header failed after 3 seconds"
  2848.           RETURN .F.
  2849.        ELSE
  2850.           ? "Error: " + str( error_no, 4 )
  2851.           RETURN .F.
  2852.        ENDIF
  2853.     ENDIF
  2854.  
  2855.  
  2856.  
  2857. See Also: V_USE() V_REPLACE()
  2858.  
  2859. ───────────────────────────────────────────────────────────────────────────────
  2860.  V_TOPPTR()
  2861.  Read/Replace FlexFile data without a DBF file.
  2862. ───────────────────────────────────────────────────────────────────────────────
  2863.  
  2864.  Syntax
  2865.  
  2866.     V_TOPPTR( [<cPointer>], [<cAlias> | <nArea>] )
  2867.  
  2868.  Arguments
  2869.  
  2870.     <cPointer> (optional) is the six byte character string returned by
  2871.     V_REPLACE().  If not specified, V_TOPPTR() will return the current
  2872.     pointer stored in the header of the DBV file (see discussion below).
  2873.  
  2874.     <cAlias> or <nArea> is a DBV file alias or area specified with
  2875.     V_USE() or V_SELECT(). If omitted, the Top-Pointer will be accessed in
  2876.     the current DBV area.
  2877.  
  2878.  Description
  2879.  
  2880.     V_TOPPTR() is a special function which allows the storage of one (and
  2881.     only one) Variable Length Field without having a separate DBF file in
  2882.     which to keep the pointer to that field.
  2883.  
  2884.     Usually, you replace a six byte character field (FlexFile's version of
  2885.     a memo-field) in a DBF file with a pointer to data which is stored in a
  2886.     DBV file.  V_TOPPTR() allows you to store one pointer in the header of
  2887.     the DBV file.  This pointer can then be accessed by calling V_TOPPTR()
  2888.     with no parameters.  For example,
  2889.  
  2890.          V_RETRIEVE( V_TOPPTR() )
  2891.  
  2892.     would retrieve an array which was previously stored with V_REPLACE()
  2893.     and whose pointer was stored by V_TOPPTR().
  2894.  
  2895.     A good example of the use of this function is in storing parameters
  2896.     that your application requires at startup:  Things like colors, default
  2897.     paths, printer definitions, etc.
  2898.  
  2899.     Many routines have been written to handle this kind of data.  MEM files
  2900.     are used by some, while others use a large DBF field and parse out the
  2901.     various data into variables.  The fact is that MEM files are not
  2902.     "network ready" and the DBF file is not efficient to handle data that
  2903.     is not repetitive in size and type. So an easy solution is to keep an
  2904.     array of these items in a DBV file and point to that array with
  2905.     V_TOPPTR().
  2906.  
  2907.     Using V_TOPPTR() requires a slightly different syntax than a standard
  2908.     replace.  Typically, a DBV replace is made by calling V_REPLACE() and
  2909.     putting the return pointer in a DBF field as follows:
  2910.  
  2911.          REPLACE vlf WITH V_REPLACE( aStartUp, vlf )
  2912.  
  2913.     where aStartUp is an array holding your applications startup data.  In
  2914.     contrast, the following syntax is required when storing the
  2915.     pointer-field directly in the DBV:
  2916.  
  2917.          V_TOPPTR( V_REPLACE( aStartUp, V_TOPPTR() ) )
  2918.  
  2919.     The logic here can best be seen by breaking this last line into several
  2920.     lines of code:
  2921.  
  2922.          // First, get the old pointer stored in the DBV file.
  2923.          cOldPointer = V_TOPPTR()
  2924.  
  2925.          // Then replace the old array with a new one.  Put
  2926.          // the pointer to the new array into the variable
  2927.          // cNewPointer.
  2928.          cNewPointer = V_REPLACE( aStartUp, cOldPointer )
  2929.  
  2930.          // Finally, store the actual pointer in the DBV.
  2931.          // This will overwrite the old pointer stored there.
  2932.          V_TOPPTR( cNewPointer )
  2933.  
  2934.  Examples
  2935.  
  2936.     LOCAL ray
  2937.  
  2938.     // Open only a DBV file
  2939.     V_USE( "dbv_file" )  // Is created if it does not exist.
  2940.  
  2941.     // Declare an array and put some junk into it.
  2942.     ray = { { "one", "two", "three" }     ,;
  2943.             { 1, 2, 3 )                   ,;
  2944.             { p1, p2, p3 }                 }
  2945.  
  2946.     // Store the array in DBV file and its pointer in
  2947.     // the header of the same DBV.
  2948.     V_TOPPTR( V_REPLACE( ray, V_TOPPTR() ) )
  2949.  
  2950.  
  2951. See Also: V_REPLACE() V_RETRIEVE()
  2952.  
  2953.  
  2954.  
  2955. ───────────────────────────────────────────────────────────────────────────────
  2956.  V_TYPE()
  2957.  Return the type of data stored in a VLF
  2958. ───────────────────────────────────────────────────────────────────────────────
  2959.  
  2960.  Syntax
  2961.  
  2962.     V_TYPE(  <cPointer>,
  2963.              <nArea> | <cAlias> )   ->   cType
  2964.  
  2965.  Arguments
  2966.  
  2967.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  2968.     memo-field).
  2969.  
  2970.     <nArea> or <cAlias> refers to the number or name of the target DBV
  2971.     work area. If not specified, the current DBV work area is assumed.
  2972.  
  2973.  Returns
  2974.  
  2975.     V_TYPE() returns the type of the data that is pointed to by
  2976.     <cPointer>. The possible types and their one character pneumonic
  2977.     are detailed in the table under the V_REPLACE() function.
  2978.  
  2979.  Description
  2980.  
  2981.     V_TYPE() is similar to Clipper's TYPE() function. There are,
  2982.     however, more "types" of data that can be stored to a VLF than in
  2983.     a Clipper memory variable. For example, Clipper see's a Proclip
  2984.     window handle as a numeric. Clipper's TYPE("pw_handle") function
  2985.     would return a 'N'. However, if you save the Proclip window to a
  2986.     VLF (See V_REPLACE()), the V_TYPE() function will return a 'P'.
  2987.  
  2988.  
  2989.  Examples
  2990.  
  2991.     // Setup seven variables of differing types.
  2992.     LOCAL num_var   ,;
  2993.           chr_var   ,;
  2994.           date_var  ,;
  2995.           log_var   ,;
  2996.           arr_var   ,;
  2997.           ffa_var   ,;
  2998.           pcw_var
  2999.  
  3000.     num_var = 5
  3001.     chr_var = "This is a test"
  3002.     date_var= DATE()
  3003.     log_var = (.T.)
  3004.     arr_var = { "Cindy", "Gail", "Edith" }
  3005.     ffa_var = A_DECLARE( 'S', 5, 5 )// FlexFile double type
  3006.     pcw_var = WNDCREATE( 5, 10 ) // Proclip window.
  3007.  
  3008.     // Open a DBF file and its associated DBV file
  3009.     USE dbf_file
  3010.     V_USE( "dbv_file" )
  3011.  
  3012.     // Replace the VLF with five different data types.
  3013.     APPEND BLANK
  3014.     REPLACE vlf WITH V_REPLACE( num_var, vlf )
  3015.     ? V_TYPE( vlf )              // Result: 'N'
  3016.  
  3017.     REPLACE vlf WITH V_REPLACE( chr_var, vlf )
  3018.     ? V_TYPE( vlf )              // Result: 'C'
  3019.  
  3020.     REPLACE vlf WITH V_REPLACE( date_var, vlf )
  3021.     ? V_TYPE( vlf )              // Result: 'D'
  3022.  
  3023.     REPLACE vlf WITH V_REPLACE( log_var, vlf )
  3024.     ? V_TYPE( vlf )              // Result: 'L'
  3025.  
  3026.     REPLACE vlf WITH V_REPLACE( arr_var, vlf )
  3027.     ? V_TYPE( vlf )              // Result: 'A'
  3028.  
  3029.     // Note: You must declare the type for a V_REPLACE()
  3030.     //    of a flexfile strongly typed array.
  3031.     REPLACE vlf WITH V_REPLACE( ffa_var, vlf, , 'F' )
  3032.     ? V_TYPE( vlf )              // Result: 'F'
  3033.  
  3034.     // Note: You must declare the type for a V_REPLACE()
  3035.     //       of a Proclip window handle.
  3036.     REPLACE vlf WITH V_REPLACE( pcw_var, vlf, , 'P' )
  3037.     ? V_TYPE( vlf )              // Result: 'P'
  3038.  
  3039.  
  3040.  
  3041. See Also: V_REPLACE() V_RETRIEVE() V_LEN()
  3042.  
  3043.  
  3044.  
  3045. ───────────────────────────────────────────────────────────────────────────────
  3046.  V_USE()
  3047.  Open/Create a Variable Length Field file (DBV)
  3048. ───────────────────────────────────────────────────────────────────────────────
  3049.  
  3050.  Syntax
  3051.  
  3052.     V_USE(   [<cFileName>],
  3053.              [<cAlias>],
  3054.              [<cNewArea>],
  3055.              [<lExclusive>] )   ->    nArea
  3056.  
  3057.  Arguments
  3058.  
  3059.     <cFileName> is the name of the file to be opened/created. A .DBV
  3060.     extension is assumed if none is provided. If the file does not
  3061.     exist, one will be created. If <cFileName> is omitted, any file
  3062.     open in the current DBV area will be closed.
  3063.  
  3064.     <cAlias> is a name to be associated with the DBV work area of the
  3065.     file being opened. If this parameter is not passed or a "dummy"
  3066.     argument is passed, the alias defaults to the DBV file name.
  3067.  
  3068.     <cNewArea> is the word "NEW". This has the same affect as issuing
  3069.     a SELECT 0 in Clipper or V_SELECT(0) in FlexFile just before
  3070.     opening the file. In Clipper version 5.0, <cNewArea> has the same
  3071.     effect as the NEW modifier of the USE command. If this parameter
  3072.     is not specified, any DBV file open in the current DBV work area
  3073.     will be closed and the <cFileName> file will be opened in its
  3074.     place.
  3075.  
  3076.     <lExclusive> is a logical expression determining the accessibility
  3077.     of the file by other users in a network environment.  If
  3078.     <lExclusive> is (.T.) and the file is successfully opened, any
  3079.     attempt by another user to V_USE() the <cFileName> file will be
  3080.     denied until the file is V_CLOSED(). If this parameter is omitted,
  3081.     FlexFile will attempt to open the <cFileName> file according to
  3082.     the current setting of V_EXCLUSIV().
  3083.  
  3084.  Returns
  3085.  
  3086.     If successful, V_USE() returns the DBV area in which the file was
  3087.     opened. Otherwise, it will return a -1 and set an error code which
  3088.     may be fetched with V_ERROR(). (See appendix B for a list of error
  3089.     codes.)
  3090.  
  3091.  Description
  3092.  
  3093.     V_USE() opens (or creates if the file does not exist) a file that
  3094.     can store variable length data. Any file which is already open in
  3095.     the DBV area is closed before the <cFileName> file is opened.
  3096.  
  3097.     Although it is far more flexible, using a DBV file is very similar
  3098.     to using memo-fields and a DBT file. It is not required but highly
  3099.     recommended that you have a DBF file open simultaneously with the
  3100.     DBV file. You will then store pointers in fields of the DBF file
  3101.     that point to variable length data in the DBV file. The fields in
  3102.     the DBF file cannot be defined as a <memo> fields but have the
  3103.     same basic functionality.
  3104.  
  3105.     Unlike the DBT file, FlexFile supports one to one, one to many,
  3106.     and many to many relationships between the DBF field pointers and
  3107.     the DBV files. For example, a system could use one DBV file to
  3108.     store all its help text, random memo's, screens and arrays. The
  3109.     pointers to all this data could be stored in several different DBF
  3110.     files. Likewise, one DBF file may point into several DBV files. It
  3111.     is left up to the programmer to keep straight which DBF fields
  3112.     relate to which DBV files.  (Note: it is a critical error to use a
  3113.     pointer which points into one DBV file as a pointer into a
  3114.     different DBV file.)
  3115.  
  3116.     If a DBV file is opened exclusively in a network environment, no
  3117.     other users may access the file until it is V_CLOSED().  Likewise,
  3118.     if the file is currently being used exclusively by another user,
  3119.     attempts to V_USE() that file will fail.  V_USE() returns -1 if
  3120.     the file is not opened and reports the error which can be fetched
  3121.     with V_ERROR().  (See appendix B for a list of error codes.)
  3122.  
  3123.     If the file is opened non-exclusively, other users may access the
  3124.     variable length data simultaneously. However, because all data in
  3125.     a DBV file must be accessed by a pointer which will usually be
  3126.     stored in a DBF file, using standard Clipper locking procedures to
  3127.     protect the DBF record will protect the variable length data
  3128.     exactly as it does any field in the DBF. (See the V_REPLACE()
  3129.     function for more on locking.)
  3130.  
  3131.  Notes
  3132.  
  3133.   ■ V_USE() obeys neither the SET DEFAULT nor the SET PATH
  3134.     settings. Instead, it will use the current DOS default directory
  3135.     or any valid path specified as a part of <cFileName>.
  3136.  
  3137.   ■ Remember that your maximum number of open files must be set by
  3138.     the V_FILES() function before V_USE()ing your first DBV file. The
  3139.     valid DBV areas will then be from 1 to the value you passed to
  3140.     V_FILES(). See V_FILES() for more on defining the active number of
  3141.     files.
  3142.  
  3143.   ■ Opening the same DBV file in two work areas simultaneously is
  3144.     possible, however, don't do it.
  3145.  
  3146.   ■ Do not confuse Clipper's selected work area with FlexFile's;
  3147.     they are mutually exclusive. For example, you can have a DBF file
  3148.     open in area 2 and simultaneously have a DBV file open in
  3149.     V_SELECT() == 2. Likewise, Clipper's SELECT <n> has no effect on
  3150.     the currently selected DBV area.
  3151.  
  3152.  Examples
  3153.  
  3154.     // Assume that no files are open at this point.
  3155.     // Set the maximum number of files to three.
  3156.     #define EXCLUSIVE_ (.T.)
  3157.     V_FILES( 3 )
  3158.  
  3159.     // Open a DBV file with an alias of "MAIN_FILE" in area 1.
  3160.     // If dbv_file.dbv does not exist it will be created.
  3161.     V_SELECT(1)
  3162.     V_USE( "dbv_file", "MAIN_FILE" )
  3163.     ? V_ALIAS()           // Result: MAIN_FILE
  3164.  
  3165.     // Open another file in the next available area.
  3166.     V_USE( "second", , "NEW" )
  3167.     ? V_SELECT()          // Result: 2
  3168.  
  3169.     // Open a third file for use on a network and test to
  3170.     // make certain that the file was properly opened.
  3171.     IF V_USE( "F:\GEN\JUNK\third", , "new", !EXCLUSIVE_ ) == -1
  3172.        ? "Error: " + str( V_ERROR(), 4 )
  3173.        QUIT
  3174.     ENDIF
  3175.  
  3176.     // Close all files.
  3177.     V_CLOSE( 1 )          // Closes file in area 1
  3178.     V_CLOSEALL()          // Closes the other two files.
  3179.  
  3180.  
  3181. See Also: V_CLOSE() V_SELECT()
  3182.  
  3183.  
  3184.  
  3185. ───────────────────────────────────────────────────────────────────────────────
  3186.  V_VLF2FILE()
  3187.  Create a DOS file and fill it with the contents of a VLF
  3188. ───────────────────────────────────────────────────────────────────────────────
  3189.  
  3190.  Syntax
  3191.  
  3192.     V_VLF2FILE(  <cFileName>,
  3193.                  <cPointer>,
  3194.                  <cMode>  )     ->    lSuccess
  3195.  
  3196.  Arguments
  3197.  
  3198.     <cFileName> is the name of a file to append to or overwrite with
  3199.     the data from a VLF associated with <cPointer>.
  3200.  
  3201.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  3202.     memo-field).
  3203.  
  3204.     <cMode> is a character code telling FlexFile to <A>ppend or
  3205.     <O>verwrite any existing file with the same name as <cFileName>.
  3206.     The default mode is <A>ppend.
  3207.  
  3208.  Returns
  3209.  
  3210.     V_VLF2FILE() returns (.T.) if the data was copied successfully,
  3211.     otherwise, it returns (.F.).
  3212.  
  3213.  Description
  3214.  
  3215.     V_VLF2FILE() copies a Variable Length Field from a DBV type file
  3216.     to a DOS file. This is particularly useful when using graphics
  3217.     applications from within Clipper that require individual files for
  3218.     images.
  3219.  
  3220.  
  3221.  Examples
  3222.  
  3223.     // Setup variable
  3224.     LOCAL pic_name
  3225.  
  3226.     // Open a DBF, NTX and DBV library of graphics images.
  3227.     USE ( pic_lib ) INDEX ( pic_lib )
  3228.     V_USE( pic_lib )
  3229.  
  3230.     // Allow the user to enter the name of a graphic image
  3231.     // to view, create a temporary disk file, print the
  3232.     // file to screen.
  3233.  
  3234.     WHILE ( .T. )
  3235.        pic_name = SPACE(11)
  3236.        @ 5, 5 SAY "Enter the image name to view: " GET pic_name
  3237.        SEEK pic_name
  3238.        IF FOUND()
  3239.  
  3240.           // Write DBV data to a temporary file.
  3241.           V_VLF2FILE( "graphic.pic", vlf_ptr )
  3242.  
  3243.           // Use one of the graphic function libraries to retrieve a file.
  3244.           file2graph( 0, "graphic.pic" )
  3245.  
  3246.           INKEY(0)
  3247.  
  3248.        ELSEIF LASTKEY() == 27
  3249.           EXIT
  3250.  
  3251.        ELSE
  3252.           ? "Image not found"
  3253.  
  3254.        ENDIF
  3255.     ENDDO
  3256.  
  3257.  
  3258. See Also: V_FILE2VLF() V_REPLACE() V_DELETE()
  3259.  
  3260.  
  3261. ───────────────────────────────────────────────────────────────────────────────
  3262.  V_WALK_DBV()
  3263.  Step from field to field in a DBV without a DBF.
  3264. ───────────────────────────────────────────────────────────────────────────────
  3265.  
  3266.  Syntax
  3267.  
  3268.     V_WALK_DBV( [<cTopOfFile>], [<cAlias> | <nArea>] )  ->   cPointer
  3269.  
  3270.  Arguments
  3271.  
  3272.     <cTopOfFile> should be the word "First" (only the "F" is significant)
  3273.     to return the pointer to the first field in a DBV.  Any other value
  3274.     (including NIL) will tell V_WALK_DBV() to skip to the next field.
  3275.  
  3276.     <cAlias> or <nArea> is a DBV file alias or area specified with
  3277.     V_USE() or V_SELECT(). If omitted, the operation will occur in the
  3278.     current DBV area.
  3279.  
  3280.  Returns
  3281.  
  3282.     This function returns a pointer to the current VLF. (See discussion
  3283.     below).  The return value is a NULL string ("") when the end of file is
  3284.     reached or when an error is encountered in the DBV.
  3285.  
  3286.  Description
  3287.  
  3288.     V_WALK_DBF() is a disaster recovery function and should rarely if every
  3289.     be needed.  However, if you loose a DBF file and still want to recover
  3290.     the contents of the DBV, this function can be indispensible.
  3291.  
  3292.     When called for the first time or when <cTopOfFile> is given the
  3293.     value "first", V_WALK_DBV() will return a pointer to the first Variable
  3294.     Length Field in the DBV (this is the first physical field).  Any
  3295.     subsequent call to this function (where <cTopOfFile> is not
  3296.     "first"), V_WALK_DBV() will return a pointer to the next physical field
  3297.     in the DBV.
  3298.  
  3299.     Thus, when put in a loop, you can walk through every field in a DBV and
  3300.     retrieve a valid FlexFile pointer for use with V_RETRIEVE(),
  3301.     V_REPLACE(), etc.
  3302.  
  3303.  Examples
  3304.  
  3305.     LOCAL vlf_ptr, str := ""
  3306.  
  3307.     // Open the DBV without opening a DBF.
  3308.     V_USE( "lost_dbf.dbv" )
  3309.  
  3310.     // Put the pointer to the first field in the variable <vlf_ptr>.
  3311.     // The "First" is not necessary here because the first call to this
  3312.     // function starts on the first field anyway, but is included
  3313.     // for clarity.
  3314.     vlf_ptr = V_WALK_DBV( "First" )
  3315.  
  3316.     DO WHILE !EMPTY( vlf_ptr )
  3317.  
  3318.        str = V_RETRIEVE( vlf_ptr )
  3319.        MEMOEDIT( str, 5, 5, 20, 75 )
  3320.  
  3321.        // Get a pointer to the next field (fields are in physical order)
  3322.        vlf_ptr = V_WALK_DBV()
  3323.  
  3324.     ENDDO
  3325.  
  3326.  
  3327.  
  3328. See Also: V_RETRIEVE()
  3329.  
  3330.  
  3331. ───────────────────────────────────────────────────────────────────────────────
  3332.  V_WNDCREAT()
  3333.  Create a Proclip(tm) window from one which was saved to a DBV file.
  3334. ───────────────────────────────────────────────────────────────────────────────
  3335.  
  3336.  Syntax
  3337.  
  3338.     V_WNDCREAT(  <cPointer>, [<cAlias> | <nArea>] )  ->   nPCWhandle
  3339.  
  3340.  Arguments
  3341.  
  3342.     <cPointer> is a six byte pointer-field (FlexFile's version of a
  3343.     memo-field).
  3344.  
  3345.     <cAlias> or <nArea> is a DBV file alias or area specified with
  3346.     V_USE() or V_SELECT(). If omitted, the operation will occur in the
  3347.     current DBV area.
  3348.  
  3349.  Returns
  3350.  
  3351.     If V_WNDCREAT() is successful, it will return a valid Proclip
  3352.     window "handle".  Otherwise, it will return 0.
  3353.  
  3354.  Description
  3355.  
  3356.     V_WNDCREAT() will re-create a Proclip window that was previously
  3357.     stored in a DBV file with the V_REPLACE() function.  The window
  3358.     will have all the attributes of the original window with the single
  3359.     exception that it will not be opened even if it was open when it
  3360.     was saved.
  3361.  
  3362.     In order to open or modify the window, you will need the Proclip
  3363.     library from Genesis Development Corporation.  It is one of the
  3364.     finest windowing libraries available.
  3365.  
  3366.  
  3367.  Examples
  3368.  
  3369.     // Create a Proclip window using the Proclip library.
  3370.     handle = WNDCREATE( 10, 20 )
  3371.  
  3372.     // Put some junk on the window.
  3373.     FOR x = 1 TO 10
  3374.        WNDPRINT( handle, x - 1, 0, "this is a test" )
  3375.     NEXT x
  3376.  
  3377.     // Show the user the window.
  3378.     WNDOPEN( handle )
  3379.  
  3380.     // Save the window to the DBV file open in the current area.
  3381.     // Note the necessity to "type" the replace (i.e. the 4th parameter).
  3382.     REPLACE vlf WITH V_REPLACE( handle, vlf, .t., 'P' )
  3383.  
  3384.     // Close and then destroy the window.
  3385.     WNDCLOSE( vlf )
  3386.     WNDDESTROY( vlf )
  3387.  
  3388.     // Now re-create the same window.
  3389.     handle = V_WNDCREAT( vlf )
  3390.  
  3391.     // Re-display the window
  3392.     WNDSHOW( handle )
  3393.  
  3394.  
  3395.  
  3396. See Also: V_FILE2VLF() V_REPLACE() V_DELETE()
  3397.  
  3398.  
  3399.  
  3400. ───────────────────────────────────────────────────────────────────────────────
  3401.  A_()
  3402.  Return a pointer reference to a multi-dimensional array element
  3403. ───────────────────────────────────────────────────────────────────────────────
  3404.  
  3405.  Syntax
  3406.  
  3407.     A_(   <nElements>,
  3408.           [, <nElements>...] )    ->    nPointer
  3409.  
  3410.  Arguments
  3411.  
  3412.     <nElements> represents the magnitude of each successive dimension
  3413.     in a FlexFile array.
  3414.  
  3415.  Returns
  3416.  
  3417.     A_() returns a character string which FlexFile interprets as a
  3418.     pointer to the specific element.
  3419.  
  3420.  Description
  3421.  
  3422.     Use A_() to simplify passing/receiving multi-dimensional array
  3423.     index references. The need for the function arises because array
  3424.     indexes have as many components as the array has dimensions and
  3425.     the passing of the index to a function can get confusing (both for
  3426.     the programmer and FlexFile's error checking).
  3427.  
  3428.     With Clipper arrays the compiler handles references to a
  3429.     particular element with the familiar syntax [ 1 ][ 1 ][ 1 ] for
  3430.     the first element of a three dimensional array.  Avoiding conflict
  3431.     with this syntax, FlexFile refers to the same element of a
  3432.     FlexFile three dimensional array as A_( 1, 1, 1 ).
  3433.  
  3434.     Although FlexFile functions will accept a numeric integer as an
  3435.     array index designator (it is the preferred method on a FlexFile
  3436.     single dimensional array), you should not use integers as indexes
  3437.     to multi- dimensional arrays.  This is because A_( 3, 5 ) does not
  3438.     refer to the same element as A_(5, 3), and rarely if ever does
  3439.     (3 * 5) point to element A_(3, 5).
  3440.  
  3441.     See the examples for a complete understanding of the use of this
  3442.     function.
  3443.  
  3444.  
  3445.  Examples
  3446.  
  3447.     // Accessing elements of a FlexFile Multi-dimensional array
  3448.     // First declare a two dimensional 5 x 10 array.
  3449.     rows = 5
  3450.     cols = 10
  3451.     aName = A_DECLARE( 'F', rows, cols )
  3452.  
  3453.     // Fill the array starting at the first element a_( 1, 1 ).
  3454.     A_FILL( aName, 98.6, A_( 1, 1 ), rows * cols )
  3455.  
  3456.     // Retrieve a value from a specified element.
  3457.     temp = A_RETRIEVE( aName, A_( 3, 2 ) )
  3458.  
  3459.  
  3460. See Also: A_RETRIEVE() A_STORE()
  3461.  
  3462.  
  3463.  
  3464. ───────────────────────────────────────────────────────────────────────────────
  3465.  A_ADD()
  3466.  Add a new element to the end of an array
  3467. ───────────────────────────────────────────────────────────────────────────────
  3468.  
  3469.  Syntax
  3470.  
  3471.     A_ADD(   @<aTarget>,
  3472.              [<nDimension>] )   ->    lSuccess
  3473.  
  3474.  Arguments
  3475.  
  3476.     <aTarget> is the array to which you are adding new element(s).
  3477.     It MUST be passed-by-reference.  A_ADD() cannot add elements to
  3478.     a binary (logical) type array.
  3479.  
  3480.     <nDimension> is the dimension that will be increased by one.
  3481.     The default is the last dimension in the list of dimensions.
  3482.  
  3483.  Returns
  3484.  
  3485.     A_ADD() returns a (.T.) if successful, otherwise, it returns a
  3486.     (.F.).
  3487.  
  3488.  Description
  3489.  
  3490.     A_ADD() works differently than Clipper's AADD() function. This is
  3491.     because FlexFile arrays are matrices and cannot have "ragged"
  3492.     lengths in any dimension.
  3493.  
  3494.     So, A_ADD() adds one element in a one dimensional array, one row
  3495.     in a two dimensional array, one page in a three dimensional array,
  3496.     and so forth.
  3497.  
  3498.     For example, imagine a two dimensional array containing students
  3499.     grades. Along one axis are the students; along the other are the
  3500.     exams. When the semester begins the professor may not know how
  3501.     many exams there are going to be (or how to handle a new student).
  3502.     If you look at both of these situations you will understand
  3503.     FlexFile's A_ADD().
  3504.  
  3505.     Lets assume that the professor begins with 20 students and plans
  3506.     the course to consist of 5 exams:
  3507.  
  3508.     students = 20 
  3509.     exams = 5 
  3510.     array = A_DECLARE( 'I', students, exams )
  3511.  
  3512.  
  3513.     Later in the course he needs to add a new student.
  3514.  
  3515.     A_ADD( @array, 1 )
  3516.  
  3517.     The second parameter is one to tell A_ADD that we are adding a
  3518.     row of exams for a new student. The value is one because when
  3519.     we declared the array the students were the first array
  3520.     index.
  3521.  
  3522.     Later the professor needs to add another exam for all students:
  3523.  
  3524.     A_ADD( @array, 2 )
  3525.  
  3526.  
  3527.  Examples
  3528.  
  3529.     // Declare a two dimensional unsigned (T)iny integer array
  3530.     LOCAL rows, cols
  3531.     
  3532.     rows = 10
  3533.     cols = 20
  3534.     aTiny = A_DECLARE( "UT", rows, cols )
  3535.     
  3536.     // Increase the columns to 21.
  3537.     A_ADD( @aTiny, 2 )
  3538.  
  3539.  
  3540.  
  3541. See Also: A_SIZE() A_DECLARE()
  3542.  
  3543.  
  3544.  
  3545. ───────────────────────────────────────────────────────────────────────────────
  3546.  A_AVERAGE()
  3547.  Return the average of the contents of a numerical array
  3548. ───────────────────────────────────────────────────────────────────────────────
  3549.  
  3550.  Syntax
  3551.  
  3552.     A_AVERAGE(   <aTarget>,
  3553.                  [<idxPos>],
  3554.                  [<nCount>] )   ->    nAverage
  3555.  
  3556.  Arguments
  3557.  
  3558.     <aTarget> is the FlexFile array on which to perform the average.
  3559.  
  3560.     <idxPos> The index (or subscript) is the position in the target
  3561.     array at which to begin the average. The default is the first
  3562.     element.
  3563.  
  3564.     <nCount> is the number of elements to include in the average. The
  3565.     default is all element starting at <idxPos> to the end of the
  3566.     array.
  3567.  
  3568.  Returns
  3569.  
  3570.     A_AVERAGE() returns the numerical average or mean of the <aTarget>
  3571.     array.  On error, A_AVERAGE() returns 0.
  3572.  
  3573.  Description
  3574.  
  3575.     A_AVERAGE() will average all or a part of a FlexFile numeric
  3576.     array. The numeric types are (D)ouble, (F)loat, (L)ong or (UL),
  3577.     (I)nteger or (UI), and (T)iny or (UT).
  3578.  
  3579.     The averaging begins at the position pointed to by <idxPos> and
  3580.     continues for <nCount> elements. The function will wrap around
  3581.     dimensions if count extends beyond the end of the current row.
  3582.  
  3583.  
  3584.  Examples
  3585.  
  3586.     // Declare a two dimensional (L)ong integer array
  3587.     LOCAL rows, cols
  3588.     
  3589.     rows = 10
  3590.     cols = 20
  3591.     aLong = A_DECLARE( "L", rows, cols )
  3592.     
  3593.     // Fill the 5th row with 100,000 and the 6th row
  3594.     // with 200,000.
  3595.     A_FILL( aLong, 100000, A_( 5, 1 ), cols )
  3596.     A_FILL( aLong, 200000, A_( 6, 1 ), cols )
  3597.     
  3598.     // Take the average of rows 5 and six.
  3599.     ? A_AVERAGE( aLong, A_( 5, 1 ), cols * 2 )  // Result: 150000
  3600.  
  3601.  
  3602.  
  3603. See Also: A_STORE() A_RETRIEVE()
  3604.  
  3605.  
  3606.  
  3607. ───────────────────────────────────────────────────────────────────────────────
  3608.  A_COPY()
  3609.  Copy all or a portion of one array into another existing array
  3610. ───────────────────────────────────────────────────────────────────────────────
  3611.  
  3612.  Syntax
  3613.  
  3614.     A_COPY(  <aSource>,
  3615.              <aTarget>,
  3616.              [<idxPos>],
  3617.              [<nCount>],
  3618.              [<nTargetPos>] )
  3619.  
  3620.  Arguments
  3621.  
  3622.     <aSource> is the array that will be copied from.
  3623.  
  3624.     <aTarget> is the array that will be copied to.
  3625.  
  3626.     <idxPos> is the element in <aSource> where the copy will begin. The
  3627.     default is the first element in the array.
  3628.  
  3629.     <nCount> is the number of elements to copy. The default is all
  3630.     elements starting at <idxPos> until the end of the row in the
  3631.     current dimension.
  3632.  
  3633.     <nTargetPos> is the starting element position in the target array.
  3634.  
  3635.  Returns
  3636.  
  3637.     None.
  3638.  
  3639.  Description
  3640.  
  3641.     A_COPY() copies the contents of one array into another.  This is
  3642.     different than Clipper's ACOPY() which copies references to nested
  3643.     array elements. Because there are no nested array elements in a
  3644.     FlexFile array, the copy includes the smaller of the range
  3645.     specified and the size of the arrays.
  3646.  
  3647.  Examples
  3648.  
  3649.     // Declare a two dimensional (UL)ong integer array
  3650.     LOCAL rows, cols
  3651.     
  3652.     rows = 10
  3653.     cols = 20
  3654.     aSource = A_DECLARE( "UL", rows, cols )
  3655.     aTarget = A_DECLARE( "UL", rows, cols )
  3656.     
  3657.     // Fill the 5th row with 100,000 and the 6th row
  3658.     // with 200,000.
  3659.     A_FILL( aSource, 100000, A_(5, 1), cols )
  3660.     A_FILL( aTarget, 200000, A_(6, 1), cols )
  3661.     
  3662.     // Copy the 5th and 6th rows to the 2nd/3rd row of the target
  3663.     A_COPY( aSource, aTarget, A_(5, 2), cols * 2, A_(2, 1) )
  3664.  
  3665.  
  3666. See Also: A_SIZE() A_INS()
  3667.  
  3668.  
  3669.  
  3670. ───────────────────────────────────────────────────────────────────────────────
  3671.  A_DECLARE()
  3672.  Declare a FlexFile array
  3673. ───────────────────────────────────────────────────────────────────────────────
  3674.  
  3675.  Syntax
  3676.  
  3677.     A_DECLARE(   <cType>,
  3678.                  <nElement>,
  3679.                  [<nElements>...] )    ->     aArray
  3680.  
  3681.  Arguments
  3682.  
  3683.     <cType> is a code for the type of the FlexFile strongly typed
  3684.     array. (See the table below for a list of types and their codes.)
  3685.  
  3686.     <nElements> is the number of elements in each consecutive
  3687.     dimension.  An array can be declared with up to six dimensions.
  3688.  
  3689.  Returns
  3690.  
  3691.     A_DECLARE() returns a fully dimensioned FlexFile array of <cType>.
  3692.  
  3693.  Description
  3694.  
  3695.     A_DECLARE() creates a FlexFile type array.  The various data types
  3696.     that FlexFile implements are listed below.
  3697.  
  3698.     When Clipper returns a value from a function, it makes a copy of
  3699.     the value for the calling function before releasing the value
  3700.     created by the called function.  So, if you declare a FlexFile
  3701.     character array of 60,000 elements, A_DECLARE() will allocate
  3702.     memory for an array of 60,000 character elements (a little over
  3703.     60,000 bytes) and then Clipper will copy that variable requiring
  3704.     two 60,000 byte blocks to execute the function.
  3705.  
  3706.     Although this is not a problem with smaller arrays, it becomes
  3707.     significant with larger ones.  FlexFile addresses this problem by
  3708.     offering an optional syntax for this function.  Just add a new
  3709.     parameter and insert it after the type.  This parameter must be a
  3710.     previously declared character string of any length and it must be
  3711.     passed-by-reference.  The optional syntax is as follows:
  3712.  
  3713.     A_DECLARE( <cType>,
  3714.               @<aLargeArr>,
  3715.                <nElement>,
  3716.               [<nElements>...] )
  3717.  
  3718.  
  3719.     The return value when this syntax is used is undefined.  Instead,
  3720.     FlexFile will modify the <aLargeArr> variable.  Because there is
  3721.     no return value, Clipper will not duplicate the <aLargeArr>
  3722.     variable.
  3723.  
  3724.     Table: Data types
  3725.     ┌──────────────────────────────────────────────────────────────────────┐
  3726.     │ Array Type       Type  Elem/Arr  Byte/Elem Data Range                │
  3727.     ├──────────────────────────────────────────────────────────────────────┤
  3728.     │ Binary (logical)  B    520K      1 bit     .T. or .F.                │
  3729.     │ Character         C    65K       1 byte    Extended ASCII set        │
  3730.     │ Tiny Integer      T    65K       1 byte    -128 to 127               │
  3731.     │ Unsigned Tiny     UT   65K       1 byte    0 to 255                  │
  3732.     │ Integer           I    32K       2 bytes   -32,768 to 32,767         │
  3733.     │ Unsigned Integer  UI   32K       2 bytes   0 to 65,535               │
  3734.     │ Long Integer      L    16K       4 bytes   -2147483648 to 2147483647 │
  3735.     │ Unsigned Long     UL   16K       4 bytes   0 to 4,294,967,295        │
  3736.     │ Floating Point    F    16K       4 bytes   7 digit precision         │
  3737.     │ String            S    16K       4 bytes   n/a                       │
  3738.     │ Double            D    8K        8 bytes   15 digit precision        │
  3739.     └──────────────────────────────────────────────────────────────────────┘
  3740.  
  3741.  Examples
  3742.  
  3743.     // Declare a two dimensional (B)inary array
  3744.     LOCAL rows, cols
  3745.     
  3746.     rows = 10000
  3747.     cols = 20
  3748.     aBinary = A_DECLARE( "B", rows, cols )
  3749.  
  3750.     // Optional syntax. Note: A_DECLARE() has no return value.
  3751.     LOCAL aLargeArr := ''
  3752.  
  3753.     A_DECLARE( "UL", aLargeArr, 10000, 2 ) 
  3754.  
  3755.  
  3756. See Also: A_FILL() A_TYPE()
  3757.  
  3758.  
  3759.  
  3760. ───────────────────────────────────────────────────────────────────────────────
  3761.  A_DEL()
  3762.  Delete one element from an array
  3763. ───────────────────────────────────────────────────────────────────────────────
  3764.  
  3765.  Syntax
  3766.  
  3767.     A_DEL( <aTarget>, [<idxPos>], [<nCount>] )
  3768.  
  3769.  Arguments
  3770.  
  3771.     <aTarget> is the array from which an element will be deleted.
  3772.  
  3773.     <idxPos> is the position in the target array of the element to be
  3774.     deleted.
  3775.  
  3776.     <nCount> is the number of elements to shift. The default is all
  3777.     elements starting at <idxPos> until the end of the row in the
  3778.     current dimension.
  3779.  
  3780.  Returns
  3781.  
  3782.     None.
  3783.  
  3784.  Description
  3785.  
  3786.     A_DEL() is similar to Clipper's ADEL() function. The array element
  3787.     pointed to by <idxPos> is removed and <nCount> elements are
  3788.     shifted up one position. A blank element is inserted at the
  3789.     position created by the shift and filled with the default value
  3790.     based on the type of the array (see A_DECLARE()).
  3791.  
  3792.     FlexFile's multi-dimensional arrays are not nested single
  3793.     dimensional arrays. Therefore, A_DEL()eting an element has no
  3794.     other affect than shifting <nCount> elements up one position.
  3795.  
  3796.     Wrapping will occur if <nCount> goes beyond the current row
  3797.     pointed to by <idxPos>. For example, if you have a two dimensional
  3798.     array with accounts in the first dimension and 12 prior period
  3799.     amounts in the second dimension, and you wanted to operate on the
  3800.     first quarter (i.e. 3 periods), making <nCount> three times the
  3801.     number of accounts will "wrap" around three periods. See the
  3802.     discussion on arrays in chapter 2 for more information on this
  3803.     feature.
  3804.  
  3805.  
  3806.  Examples
  3807.  
  3808.     // Declare a two dimensional (C)haracter array
  3809.     LOCAL rows, cols, x, y, z
  3810.     
  3811.     rows = 10
  3812.     cols = 20
  3813.     z = 1
  3814.     aChar = A_DECLARE( "C", rows, cols )
  3815.     
  3816.     // Fill the array with increasing character values.
  3817.     FOR x = 1 to rows
  3818.        FOR y = 1 to cols
  3819.           z++
  3820.           A_STORE( aChar, chr(z), A_( x, y ) )
  3821.        NEXT
  3822.     NEXT
  3823.  
  3824.     // Delete the ASCII character "" from the first element
  3825.     // and shift all elements from the second element to the
  3826.     // end of the array up one position.  Wrapping will occur.
  3827.     A_DEL( aChar, A_(1, 1), 1 )
  3828.  
  3829.  
  3830.  
  3831. See Also: A_DECLARE() A_INS() A_SCROLL()
  3832.  
  3833.  
  3834.  
  3835. ───────────────────────────────────────────────────────────────────────────────
  3836.  A_DIMS()
  3837.  Return the number of dimensions in an array
  3838. ───────────────────────────────────────────────────────────────────────────────
  3839.  
  3840.  Syntax
  3841.  
  3842.     A_DIMS( <aTarget> )   ->   nDimensions
  3843.  
  3844.  Arguments
  3845.  
  3846.     <aTarget> is the array whose dimensions are being queried.
  3847.  
  3848.  Returns
  3849.  
  3850.     A_DIMS() returns the number of dimensions of <aTarget>.
  3851.  
  3852.  Description
  3853.  
  3854.     A_DIMS() is used to query an array returning the number of
  3855.     dimensions that were used when the array was A_DECLARE()d.
  3856.  
  3857.  
  3858.  Examples
  3859.  
  3860.     // Declare a four dimensional (S)tring array
  3861.     LOCAL books, pages, rows, cols
  3862.     
  3863.     books = 2
  3864.     pages = 10
  3865.     rows = 15
  3866.     cols = 50
  3867.     aString = A_DECLARE( "S", books, pages, rows, cols )
  3868.     
  3869.     ? A_DIMS( aString )          // Result: 4
  3870.  
  3871.  
  3872.  
  3873.  
  3874. See Also: A_DECLARE() A_LEN()
  3875.  
  3876.  
  3877.  
  3878. ───────────────────────────────────────────────────────────────────────────────
  3879.  A_DIVIDE()
  3880.  Divide all elements of an array by a value or an array of values
  3881. ───────────────────────────────────────────────────────────────────────────────
  3882.  
  3883.  Syntax
  3884.  
  3885.     A_DIVIDE(    <aTarget>,
  3886.                  <nDenominator> | <aDenominators>,
  3887.                  [<aSource>] )
  3888.  
  3889.  Arguments
  3890.  
  3891.     <aTarget> is the array to be modified. If <aSource> is not
  3892.     specified then each element of <aTarget> is the numerator of the
  3893.     division.
  3894.  
  3895.     <nDenominator> or <aDenominators> is either a value or an array of
  3896.     values used as the denominator in the division.
  3897.  
  3898.     <aSource> is an optional array of numerators. If not specified,
  3899.     then each element of <aTarget> will be used as the numerator of
  3900.     the division.
  3901.  
  3902.  Returns
  3903.  
  3904.     Although there is no return value, the <aTarget> array is
  3905.     modified.
  3906.  
  3907.  Description
  3908.  
  3909.     A_DIVIDE() provides a means to perform a division of every element
  3910.     in the <aSource> array if specified or the <aTarget> array if not.
  3911.     Each element of the <aSource> or <aTarget> array is divided by the
  3912.     <nDenominator> or element for element by <aDenominator>. The
  3913.     result of the division replaces the value in the <aTarget> array.
  3914.  
  3915.     A_DIVIDE() can be performed on any integer or floating point type
  3916.     array. These include the (T)iny, (I)integer, (L)ong, (F)loat and
  3917.     (D)ouble (both signed and unsigned integers, of course).  Mixing
  3918.     of the various numeric types is permitted, however, the source
  3919.     values are promoted or demoted to the targets type before the
  3920.     operation is executed.
  3921.  
  3922.     Division by zero is trapped and the element in error is replaced
  3923.     with zero.
  3924.  
  3925.  Notes
  3926.  
  3927.   ■ Division by zero is trapped and the element in error is
  3928.   replaced with zero.
  3929.  
  3930.  Examples
  3931.     // Declare three double type arrays for this function.
  3932.     LOCAL rows, cols
  3933.     
  3934.     rows = 10
  3935.     cols = 20
  3936.     aSource = A_DECLARE( "D", rows, cols )
  3937.     aTarget = A_DECLARE( "D", rows, cols )
  3938.     aDenominator = A_DECLARE( "D", rows, cols )
  3939.     
  3940.     // Fill the target array with 10's
  3941.     A_FILL( aTarget, 10, A_(1, 1), rows * cols )
  3942.     
  3943.     // Divide every element in the target array by 2
  3944.     A_DIVIDE( aTarget, 2 )
  3945.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 5.0
  3946.     
  3947.     // Fill the source array with 10's
  3948.     A_FILL( aSource, 10, A_(1, 1), rows * cols )
  3949.     
  3950.     // Divide every element in the source array by five and
  3951.     // put the result in the target array.
  3952.     A_DIVIDE( aTarget, 5, aSource )
  3953.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 2.0
  3954.     
  3955.     // Fill the denominator array with 4's
  3956.     // Remember the source array still has all 10's
  3957.     A_FILL( aDenominator, 4, A_(1, 1), rows * cols )
  3958.     
  3959.     // Divide every element in the source array by every element
  3960.     // in the denominator array and put the result in the target
  3961.     // array.
  3962.     A_DIVIDE( aTarget, aDenominator, aSource )
  3963.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 2.5
  3964.  
  3965.  
  3966. See Also: A_MULTIPLY() A_PLUS() A_MINUS()
  3967.  
  3968.  
  3969.  
  3970.  
  3971. ───────────────────────────────────────────────────────────────────────────────
  3972.  A_ERROR()
  3973.  Report specific error codes from FlexFile's error system
  3974. ───────────────────────────────────────────────────────────────────────────────
  3975.  
  3976.  Syntax
  3977.  
  3978.     A_ERROR()   ->    nErrorValue
  3979.  
  3980.  Arguments
  3981.  
  3982.     None.
  3983.  
  3984.  Returns
  3985.  
  3986.     A_ERROR() returns a FlexFile error code as a numeric integer.
  3987.  
  3988.  Description
  3989.  
  3990.     A_ERROR() is an error function that will return the most recent
  3991.     error code that FlexFile set. If the failed operation has no
  3992.     FlexFile error code check the DOS error code using Clipper's
  3993.     DOSERROR().
  3994.  
  3995.     For a complete list of error codes and their descriptions
  3996.     refer to Appendix B.
  3997.  
  3998.  Examples
  3999.  
  4000.     // Declare a two dimensional array
  4001.     LOCAL aLong
  4002.     aLong = A_DECLARE( 'L', 5, 7 )
  4003.  
  4004.     // Using A_KILL() on a non-string type array is an error.
  4005.     A_KILL( aLong )
  4006.  
  4007.     // Show the error code for a type mismatch.
  4008.     ? A_ERROR()                   // Result: 2001
  4009.  
  4010.  
  4011. See Also: errcodes.ngo:"Error Codes"
  4012.  
  4013.  
  4014.  
  4015. ───────────────────────────────────────────────────────────────────────────────
  4016.  A_FILL()
  4017.  Fill all or a portion of an array with a specified value
  4018. ───────────────────────────────────────────────────────────────────────────────
  4019.  
  4020.  Syntax
  4021.  
  4022.     A_FILL(  <aTarget>,
  4023.              <expValue>,
  4024.              [<idxPos>],
  4025.              [<nCount>] )
  4026.  
  4027.  Arguments
  4028.  
  4029.     <aTarget> is the array which will be filled.
  4030.  
  4031.     <expValue> is an expression which must evaluate to the same type
  4032.     as that of the array. This value will be placed in each element of
  4033.     the fill range.
  4034.  
  4035.     <idxPos> is the first position to in the <aTarget> array to fill.
  4036.     If not specified, the default value is the first element in the array.
  4037.  
  4038.     <nCount> is the number of elements to fill starting at <idxPos>.
  4039.     If not specified, elements are filled to the end of the array.
  4040.  
  4041.  Returns
  4042.  
  4043.     None.
  4044.  
  4045.  Description
  4046.  
  4047.     A_FILL() replaces <nCount> elements in the range beginning at
  4048.     <idxPos> with <expValue>. The value must be of the same type as
  4049.     the array.
  4050.  
  4051.     Wrapping will occur if <nCount> goes beyond the current row
  4052.     pointed to by <idxPos>. For example, if you have a two dimensional
  4053.     array with accounts in the first dimension and 12 prior period
  4054.     amounts in the second dimension, and you wanted to operate on the
  4055.     first quarter (i.e. 3 periods), making <nCount> three times the
  4056.     number of accounts will "wrap" around three periods. See the
  4057.     discussion on arrays in chapter 2 for more information on this
  4058.     feature.
  4059.  
  4060.  
  4061.  Examples
  4062.  
  4063.     // Declare a two dimensional (F)loating point array
  4064.     LOCAL rows, cols
  4065.     
  4066.     rows = 10
  4067.     cols = 20
  4068.     aFloat = A_DECLARE( "F", rows, cols )
  4069.     
  4070.     // Fill the second row of the array with 98.6
  4071.     A_FILL( aFloat, 98.6, A_(2, 1), cols )
  4072.  
  4073.  
  4074. See Also: A_STORE() A_ADD()
  4075.  
  4076.  
  4077.  
  4078. ───────────────────────────────────────────────────────────────────────────────
  4079.  A_INS()
  4080.  Insert an element into an array
  4081. ───────────────────────────────────────────────────────────────────────────────
  4082.  
  4083.  Syntax
  4084.  
  4085.     A_INS( <aTarget>, [<idxPos>], [<nCount>] )
  4086.  
  4087.  Arguments
  4088.  
  4089.     <aTarget> is the array into which an element will be inserted.
  4090.  
  4091.     <idxPos> is the position in the target array of the element to be
  4092.     inserted.
  4093.  
  4094.     <nCount> is the number of elements to shift. The default is all
  4095.     elements starting at <idxPos> until the end of the row in the
  4096.     current dimension.
  4097.  
  4098.  Returns
  4099.  
  4100.     None.
  4101.  
  4102.  Description
  4103.  
  4104.     A_INS() is similar to Clipper's AINS() function. All elements from
  4105.     <idxPos> for <nCount> will be shifted down one element. The last
  4106.     element in <nCount> will be pushed into oblivion. A blank element
  4107.     is inserted at the position created by the shift and filled with
  4108.     the default value based on the type of the array (see
  4109.     A_DECLARE()).
  4110.  
  4111.     FlexFile's multi-dimensional arrays are not nested single
  4112.     dimensional arrays. Therefore, A_INS()erting an element has no
  4113.     other affect than shifting <nCount> elements down one position.
  4114.  
  4115.     Wrapping will occur if <nCount> goes beyond the current row
  4116.     pointed to by <idxPos>. For example, if you have a two dimensional
  4117.     array with accounts in the first dimension and 12 prior period
  4118.     amounts in the second dimension, and you wanted to operate on the
  4119.     first quarter (i.e. 3 periods), making <nCount> three times the
  4120.     number of accounts will "wrap" around three periods. See the
  4121.     discussion on arrays in chapter 2 for more information on this
  4122.     feature.
  4123.  
  4124.  Examples
  4125.  
  4126.     // Declare a two dimensional (C)haracter array
  4127.     LOCAL rows, cols, x, y, z
  4128.     
  4129.     rows = 10
  4130.     cols = 20
  4131.     z = 1
  4132.     aChar = A_DECLARE( "C", rows, cols )
  4133.     
  4134.     // Fill the array with increasing character values.
  4135.     FOR x = 1 to rows
  4136.        FOR y = 1 to cols
  4137.           z++
  4138.           A_STORE( aChar, chr(z), A_( x, y ) )
  4139.        NEXT
  4140.     NEXT
  4141.  
  4142.     // Insert four blank elements (chr(0)'s) at the first element
  4143.     // and shift all elements from the second element to the
  4144.     // end of the array down four positions.  Wrapping will occur.
  4145.     A_INS( aChar, A_(1, 1), 4 )
  4146.  
  4147.  
  4148. See Also: A_DECLARE() A_DEL() A_SCROLL()
  4149.  
  4150.  
  4151.  
  4152. ───────────────────────────────────────────────────────────────────────────────
  4153.  A_KILL()
  4154.  Release memory for all or a range of elements from a string array
  4155. ───────────────────────────────────────────────────────────────────────────────
  4156.  
  4157.  Syntax
  4158.  
  4159.     A_KILL( <aTarget>, [<idxPos>], [<nCount>] )
  4160.  
  4161.  Arguments
  4162.  
  4163.     <aTarget> is the array in which to release elements.
  4164.  
  4165.     <idxPos> is the position in the target array of the first element
  4166.     to be released.  If not specified, A_KILL() begins at the first
  4167.     element in the array.
  4168.  
  4169.     <nCount> is the number of elements to release. The default is all
  4170.     elements starting at <idxPos> until the end of the array. This
  4171.     includes wrapping.
  4172.  
  4173.  Returns
  4174.  
  4175.     None.
  4176.  
  4177.  Description
  4178.  
  4179.     FlexFile's string arrays are actually arrays of pointers. That is,
  4180.     the array consists of four byte elements, each element capable of
  4181.     pointing to a string of data. When declared, each element of the
  4182.     array is undefined.
  4183.  
  4184.     When data is A_STORE()d to an element of a string array, memory is
  4185.     allocated for that data. If the array of pointers falls out of
  4186.     scope before that memory is released, the memory is orphaned and
  4187.     essentially lost until the application is exited.
  4188.  
  4189.     Therefore, you must use A_KILL() to release the data before
  4190.     allowing a FlexFile string array to fall out of scope.
  4191.  
  4192.     ┌────────────────────────── WARNING ───────────────────────────┐
  4193.     │ You must use A_KILL() to release the data from a String type │
  4194.     │ array before allowing the array to fall out of scope.        │
  4195.     └──────────────────────────────────────────────────────────────┘
  4196.  
  4197.  Examples
  4198.  
  4199.     // Use A_KILL() to release a FlexFile string type array
  4200.     // before exiting the function that created it.
  4201.     
  4202.     Phrase( "Miles to go before I sleep" )
  4203.     
  4204.     
  4205.     FUNCTION Phrase( cSomePhrase )
  4206.     
  4207.        LOCAL ffArray
  4208.        // Declare a FlexFile string array.
  4209.        ffArray = A_DECLARE( 'S', 5, 8 )
  4210.     
  4211.        // Put the value into element A_( 3, 3 ).
  4212.        A_STORE( ffArray, cSomePhrase, A_( 3, 3 ) )
  4213.     
  4214.        // Do something with the array.
  4215.        ? A_RETRIEVE( ffArrary, A_(3, 3) )
  4216.     
  4217.        // It is necessary to release the memory
  4218.        // allocated for the string in the array.
  4219.        A_KILL( ffArray )
  4220.     
  4221.     // The array itself is released by Clipper on return
  4222.     RETURN (.T.)
  4223.  
  4224.  
  4225. See Also: A_STORE() A_DECLARE()
  4226.  
  4227.  
  4228.  
  4229. ───────────────────────────────────────────────────────────────────────────────
  4230.  A_LEN()
  4231.  Return the total number of elements in an array or a specified dimension
  4232. ───────────────────────────────────────────────────────────────────────────────
  4233.  
  4234.  Syntax
  4235.  
  4236.     A_LEN( <aTarget>, [<nDimension>] )    ->    nCount
  4237.  
  4238.  Arguments
  4239.  
  4240.     <aTarget> is the array whose elements will be counted.
  4241.  
  4242.     <nDimension> is the dimension whose elements will be counted. If
  4243.     not specified, all elements in the array will be counted.
  4244.  
  4245.  Returns
  4246.  
  4247.     A_LEN() returns the number of elements in the array or any one
  4248.     dimension of the array.
  4249.  
  4250.  Description
  4251.  
  4252.     A_LEN() counts the number of declared elements in an array. If a
  4253.     particular dimension is supplied in <nDimension>, then only the
  4254.     number of elements in that dimension will be reported.
  4255.  
  4256.     For example, if you declare a two dimensional array with thirty
  4257.     students in the first dimension and their grades on five exams in
  4258.     the second, A_LEN() will report thirty elements for the first
  4259.     dimension, five elements in the second dimension or one hundred
  4260.     and fifty elements in the entire array.
  4261.  
  4262.  Examples
  4263.  
  4264.     // Use A_LEN() to scan for the total length of an array.
  4265.     
  4266.     LOCAL ffArray
  4267.     // Declare a FlexFile string array.
  4268.     ffArray = A_DECLARE( 'S', 5, 8 )
  4269.     
  4270.     ? A_LEN( ffArray )      // Result: 40
  4271.     
  4272.     // Now use to show only the length of the second dimension.
  4273.     ? A_LEN( ffArray, 2 )   // Result: 8
  4274.  
  4275.  
  4276. See Also: A_DECLARE() A_ADD() A_SIZE()
  4277.  
  4278.  
  4279.  
  4280. ───────────────────────────────────────────────────────────────────────────────
  4281.  A_MAX()
  4282.  Return the greatest value found in a numeric array
  4283. ───────────────────────────────────────────────────────────────────────────────
  4284.  
  4285.  Syntax
  4286.  
  4287.     A_MAX( <aTarget>, [<idxPos>], [<nCount>] )
  4288.  
  4289.  Arguments
  4290.  
  4291.     <aTarget> is the numeric type array to evaluate.
  4292.  
  4293.     <idxPos> is the position in the target array of the first element
  4294.     to be evaluated.  If not specified, A_MAX() begins its search on
  4295.     the first element of the array.
  4296.  
  4297.     <nCount> is the number of elements to evaluate. The default is all
  4298.     elements starting at <idxPos> until the end of the row in the
  4299.     current dimension.
  4300.  
  4301.  Returns
  4302.  
  4303.     A_MAX() returns an index to the element which has the maximum
  4304.     value found in the specified range.
  4305.  
  4306.  Description
  4307.  
  4308.     A_MAX() evaluates every element in the specified range of a
  4309.     numeric type array and returns an index to the largest element.
  4310.  
  4311.  Examples
  4312.  
  4313.     // Declare a two dimensional (I)nteger array
  4314.     LOCAL rows, cols, x
  4315.     
  4316.     rows = 10
  4317.     cols = 20
  4318.     aInteger = A_DECLARE( "I", rows, cols )
  4319.     
  4320.     // Fill the second row of the array with increasing
  4321.     // integer values 1 - 20
  4322.     FOR x = 1 to 20
  4323.        A_STORE( aInteger, x, A_( 2, x ) )
  4324.     NEXT
  4325.     
  4326.     // Fetch the maximum value in the first half of the
  4327.     // second row.
  4328.     ? A_MAX( aInteger, A_( 2, 1 ), cols / 2 )   // Result: 10
  4329.  
  4330. See Also: A_MIN() A_SCAN()
  4331.  
  4332.  
  4333.  
  4334. ───────────────────────────────────────────────────────────────────────────────
  4335.  A_MIN()
  4336.  Return the smallest value found in a given range of an array
  4337. ───────────────────────────────────────────────────────────────────────────────
  4338.  
  4339.  Syntax
  4340.  
  4341.     A_MIN( <aTarget>, [<idxPos>], [<nCount>] )
  4342.  
  4343.  Arguments
  4344.  
  4345.     <aTarget> is the numeric type array to evaluate.
  4346.  
  4347.     <idxPos> is the position in the target array of the first element
  4348.     to be evaluated.  If not specified, A_MIN() begins its search on
  4349.     the first element in the array.
  4350.  
  4351.     <nCount> is the number of elements to evaluate. The default is all
  4352.     elements starting at <idxPos> until the end of the row in the
  4353.     current dimension.
  4354.  
  4355.  Returns
  4356.  
  4357.     A_MIN() returns an index to the element which has the minimum
  4358.     value found in the specified range.
  4359.  
  4360.  Description
  4361.  
  4362.     A_MIN() evaluates every element in the specified range of a
  4363.     numeric type array and returns an index to that element which has
  4364.     the lowest value.
  4365.  
  4366.  
  4367.  Examples
  4368.  
  4369.     // Declare a two dimensional (UI)nteger array
  4370.     LOCAL rows, cols, x
  4371.     
  4372.     rows = 10
  4373.     cols = 20
  4374.     auInteger = A_DECLARE( "UI", rows, cols )
  4375.     
  4376.     // Fill the second row of the array with increasing
  4377.     // integer values 1 - 20
  4378.     FOR x = 1 to 20
  4379.        A_STORE( auInteger, x, A_( 2, x ) )
  4380.     NEXT
  4381.     
  4382.     // Fetch the minimum value in the first half of the
  4383.     // second row.
  4384.     ? A_MIN( auInteger, A_( 2, 1 ), cols / 2 )   // Result: 1
  4385.  
  4386.  
  4387.  
  4388. See Also: A_MAX() A_SCAN()
  4389.  
  4390.  
  4391.  
  4392. ───────────────────────────────────────────────────────────────────────────────
  4393.  A_MINUS()
  4394.  Subtract all elements of an array by a value or an array of values
  4395. ───────────────────────────────────────────────────────────────────────────────
  4396.  
  4397.  Syntax
  4398.  
  4399.     A_MINUS( <aTarget>,
  4400.              <nValue> | <aValue>,
  4401.              [<aSource>] )
  4402.  
  4403.  Arguments
  4404.  
  4405.     <aTarget> is the array to be modified.  If <aSource> is not
  4406.     specified then each element of <aTarget> will be subtracted by the
  4407.     <nValue> or element by element by <aValue>.
  4408.  
  4409.     <nValue> or <aValue> is either a value or an array of values to be
  4410.     subtracted.
  4411.  
  4412.     <aSource> is an optional array of values.  If specified, then each
  4413.     element of <aTarget> will be filled with the corresponding value
  4414.     in <aSource> subtracted by <aValue> or <nValue>.
  4415.  
  4416.  Returns
  4417.  
  4418.     Although there is no return value, the <aTarget> array is modified.
  4419.  
  4420.  Description
  4421.  
  4422.     A_MINUS() provides a means to perform a subtraction of every
  4423.     element in the <aSource> array if specified or the <aTarget> array
  4424.     if not.  Each element of the <aSource> or <aTarget> array has
  4425.     <nValue> or <aValue> subtracted from it.  The result of the
  4426.     subtraction replaces the value in the <aTarget> array.
  4427.  
  4428.     A_MINUS() can be performed on any integer or floating point type
  4429.     array. These include the (T)iny, (I)nteger, (L)ong, (F)loat and
  4430.     (D)ouble.  Mixing of these types is allowed.
  4431.  
  4432.  Notes
  4433.  
  4434.     If the <aTarget> and the <aSource> arrays are not the same
  4435.     dimensions, the results will be a subtraction element for element
  4436.     as the arrays are aligned in memory.  See chapter two for how
  4437.     arrays are aligned in memory.
  4438.  
  4439.  Examples
  4440.  
  4441.     // Declare three double type arrays for this function.
  4442.     LOCAL rows, cols
  4443.     
  4444.     rows = 10
  4445.     cols = 20
  4446.     aSource = A_DECLARE( "D", rows, cols )
  4447.     aTarget = A_DECLARE( "D", rows, cols )
  4448.     aSubMe  = A_DECLARE( "D", rows, cols )
  4449.     
  4450.     // Fill the target array with 10's
  4451.     A_FILL( aTarget, 10, A_(1, 1), rows * cols )
  4452.     
  4453.     // Subtract 2 from every element in the target array
  4454.     A_MINUS( aTarget, 2 )
  4455.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 8.0
  4456.     
  4457.     
  4458.     // Fill the source array with 10's
  4459.     A_FILL( aSource, 10, A_(1, 1), rows * cols )
  4460.     
  4461.     // Subtract five from every element in the source array and
  4462.     // put the result in the target array.
  4463.     A_MINUS( aTarget, 5, aSource )
  4464.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 5.0
  4465.     
  4466.     
  4467.     // Fill the "subtract me" array with 4's
  4468.     // Remember the source array still has all 10's
  4469.     A_FILL( aSubMe, 4, A_(1, 1), rows * cols )
  4470.     
  4471.     // Subtract from every element in the source array the
  4472.     // value in every matching element of the "subtract me"
  4473.     // array and put the result in the target array.
  4474.     A_MINUS( aTarget, aSubMe, aSource )
  4475.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 6.0
  4476.  
  4477.  
  4478. See Also: A_MULTIPLY() A_PLUS() A_DIVIDE()
  4479.  
  4480.  
  4481.  
  4482. ───────────────────────────────────────────────────────────────────────────────
  4483.  A_MULTIPLY()
  4484.  Multiply all elements of an array by a value or an array of values
  4485. ───────────────────────────────────────────────────────────────────────────────
  4486.  
  4487.  Syntax
  4488.  
  4489.     A_MULTIPLY(  <aTarget>,
  4490.                    [<nValue> | <aValues>],
  4491.                    [<aSource>] )
  4492.  
  4493.  Arguments
  4494.  
  4495.     <aTarget> is the array to be modified.  If <aSource> is not
  4496.     specified then each element of <aTarget> will be multiplied by the
  4497.     <nValue> or element by element by <aValue>.
  4498.  
  4499.     <nValue> or <aValue> is either a value or an array of values to be
  4500.     multiplied.
  4501.  
  4502.     <aSource> is an optional array of values.  If specified, then each
  4503.     element of <aTarget> will be filled with the corresponding value
  4504.     in <aSource> multiplied by <aValue> or <nValue>.
  4505.  
  4506.  Returns
  4507.  
  4508.     Although there is no return value, the <aTarget> array is modified.
  4509.  
  4510.  Description
  4511.  
  4512.     A_MULTIPLY() provides a means to perform a multiplication of every
  4513.     element in the <aSource> array if specified or the <aTarget> array
  4514.     if not. Each element of the <aSource> or <aTarget> array will be
  4515.     multiplied by <nValue> or <aValue>.  The result of the
  4516.     multiplication replaces the value in the <aTarget> array.
  4517.  
  4518.     A_MULTIPLY() can be performed on any integer or floating point
  4519.     type array.  These include the (T)iny, (I)integer, (L)ong, (F)loat
  4520.     and (D)ouble (both signed and unsigned integers, of course).
  4521.     Mixing of these types is allowed, however, if the <aTarget> array
  4522.     is of integer type, decimals will be truncated.
  4523.  
  4524.  Notes
  4525.  
  4526.     If the <aTarget> and the <aSource> arrays are not the same
  4527.     dimensions, the results will be a multiplication element for
  4528.     element as the arrays are aligned in memory.  See chapter two for
  4529.     how arrays are aligned in memory.
  4530.  
  4531.  Examples
  4532.  
  4533.     // Declare three double type arrays for this function.
  4534.     LOCAL rows, cols
  4535.     
  4536.     rows = 10
  4537.     cols = 20
  4538.     aSource = A_DECLARE( "D", rows, cols )
  4539.     aTarget = A_DECLARE( "D", rows, cols )
  4540.     aMultiplier = A_DECLARE( "D", rows, cols )
  4541.     
  4542.     // Fill the target array with 10's
  4543.     A_FILL( aTarget, 10, A_(1, 1), rows * cols )
  4544.     
  4545.     // Multiply every element in the target array by 2
  4546.     A_MULTIPLY( aTarget, 2 )
  4547.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 20.0
  4548.     
  4549.     
  4550.     // Fill the source array with 10's
  4551.     A_FILL( aSource, 10, A_(1, 1), rows * cols )
  4552.     
  4553.     // Multiply every element in the source array by five and
  4554.     // put the result in the target array.
  4555.     A_MULTIPLY( aTarget, 5, aSource )
  4556.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 50.0
  4557.     
  4558.     
  4559.     // Fill the multiplier array with 4's
  4560.     // Remember the source array still has all 10's
  4561.     A_FILL( aMultiplier, 4, A_(1, 1), rows * cols )
  4562.     
  4563.     // Multiply every element in the source array by every element
  4564.     // in the multiplier array and put the result in the target
  4565.     // array.
  4566.     A_MULTIPLY( aTarget, aMultiplier, aSource )
  4567.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 40.0
  4568.  
  4569.  
  4570.  
  4571.  
  4572. See Also: A_DIVIDE() A_PLUS() A_MINUS()
  4573.  
  4574.  
  4575.  
  4576. ───────────────────────────────────────────────────────────────────────────────
  4577.  A_PLUS()
  4578.  Add all elements of an array by a value or an array of values
  4579. ───────────────────────────────────────────────────────────────────────────────
  4580.  
  4581.  Syntax
  4582.  
  4583.     A_PLUS(  <aTarget>,
  4584.              [<nValue> | <aValues>],
  4585.              [<aSource>] )
  4586.  
  4587.  Arguments
  4588.  
  4589.     <aTarget> is the array to be modified.  If <aSource> is not
  4590.     specified then each element of <aTarget> will be added to <nValue>
  4591.     or element by element by <aValue>.
  4592.  
  4593.     <nValue> or <aValue> is either a value or an array of values to be
  4594.     added.
  4595.  
  4596.     <aSource> is an optional array of values.  If specified, then each
  4597.     element of <aTarget> will be filled with the corresponding value
  4598.     in <aSource> added to <aValue> or <nValue>.
  4599.  
  4600.  Returns
  4601.  
  4602.     Although there is no return value, the <aTarget> array is
  4603.     modified.
  4604.  
  4605.  Description
  4606.  
  4607.     A_PLUS() provides a means to perform an addition of every element
  4608.     in the <aSource> array if specified or the <aTarget> array if not.
  4609.     Each element of the <aSource> or <aTarget> array will be added to
  4610.     <nValue> or <aValue>.  The result of the addition is placed in the
  4611.     <aTarget> array.
  4612.  
  4613.     A_PLUS() can be performed on any integer or floating point type
  4614.     array. These include the (T)iny, (I)integer, (L)ong, (F)loat and
  4615.     (D)ouble (both signed and unsigned integers, of course).  Mixing
  4616.     of these types is allowed, however, if the <aTarget> array is of
  4617.     integer type, decimals will be truncated.
  4618.  
  4619.  Notes
  4620.  
  4621.     If the <aTarget> and the <aSource> arrays are not the same
  4622.     dimensions, the results will be an addition element for element as
  4623.     the arrays are aligned in memory.  See chapter two for how arrays
  4624.     are aligned in memory.
  4625.  
  4626.  Examples
  4627.  
  4628.     // Declare three double type arrays for this function.
  4629.     LOCAL rows, cols
  4630.     
  4631.     rows = 10
  4632.     cols = 20
  4633.     aSource = A_DECLARE( "D", rows, cols )
  4634.     aTarget = A_DECLARE( "D", rows, cols )
  4635.     aAddMe  = A_DECLARE( "D", rows, cols )
  4636.     
  4637.     // Fill the target array with 10's
  4638.     A_FILL( aTarget, 10, A_(1, 1), rows * cols )
  4639.     
  4640.     // Add 2 to every element in the target array
  4641.     A_ADD( @aTarget, 2 )
  4642.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 12.0
  4643.     
  4644.     
  4645.     // Fill the source array with 10's
  4646.     A_FILL( aSource, 10, A_(1, 1), rows * cols )
  4647.     
  4648.     // Add five to every element in the source array and
  4649.     // put the result in the target array.
  4650.     A_ADD( @aTarget, 5, aSource )
  4651.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 15.0
  4652.     
  4653.     
  4654.     // Fill the "add me" array with 4's
  4655.     // Remember the source array still has all 10's
  4656.     A_FILL( aAddMe, 4, A_(1, 1), rows * cols )
  4657.     
  4658.     // Add to every element in the source array the
  4659.     // value in every matching element of the "add me"
  4660.     // array and put the result in the target array.
  4661.     A_ADD( @aTarget, aAddMe, aSource )
  4662.     ? A_RETRIEVE( aTarget, A_( 4, 5 ) )    // Result: 14.0
  4663.     
  4664.  
  4665.  
  4666. See Also: A_DIVIDE() A_MULTIPLY() A_MINUS()
  4667.  
  4668.  
  4669.  
  4670. ───────────────────────────────────────────────────────────────────────────────
  4671.  A_RETRIEVE()
  4672.  Return the value of a specified element of an array
  4673. ───────────────────────────────────────────────────────────────────────────────
  4674.  
  4675.  Syntax
  4676.  
  4677.     A_RETRIEVE(  <aTarget>,
  4678.                  <idxPos> )    ->    expValue
  4679.  
  4680.  Arguments
  4681.  
  4682.     <aTarget> is the array to return a value from.
  4683.  
  4684.     <idxPos> points to the element whose value is to be returned.
  4685.  
  4686.  Returns
  4687.  
  4688.     A_RETRIEVE() returns the value of the element in <aTarget> pointed
  4689.     to by <idxPos>.  The type of the value will always be the same
  4690.     type as that of the array unless an error is encountered.  In the
  4691.     case of an error, the return value will be (.F.).
  4692.  
  4693.  Description
  4694.  
  4695.     A_RETRIEVE() is used to get the value of an element from a FlexFile
  4696.     array.
  4697.  
  4698.  Notes
  4699.  
  4700.   ■ If a numeric value was stored as a double or float, the value
  4701.     returned will be equivalent to the value stored, but if you display the
  4702.     value without a PICTURE clause, it will show the number of decimals
  4703.     according to the value of SET DECIMAL TO (which is not necesarily the
  4704.     same number of decimals that were visable when the value that was
  4705.     A_STORE()ed).
  4706.  
  4707.  
  4708.  Examples
  4709.  
  4710.     // Declare a two dimensional (UL)ong integer array
  4711.     LOCAL rows, cols
  4712.     
  4713.     rows = 10
  4714.     cols = 20
  4715.     auLong = A_DECLARE( "UL", rows, cols )
  4716.     
  4717.     // Fill the 5th row with 100,000
  4718.     A_FILL( auLong, 123456, A_(5, 1), cols )
  4719.     
  4720.     // Multiply the value in the fifth row, fourth column
  4721.     // by five and print the result.
  4722.     ? A_RETRIEVE( auLong, A_( 5, 4 ) ) * 5      // Result: 617280
  4723.  
  4724. See Also: A_STORE() A_TYPE() A_DECLARE()
  4725.  
  4726.  
  4727.  
  4728. ───────────────────────────────────────────────────────────────────────────────
  4729.  A_SCAN()
  4730.  Scan an array or part of an array for an expression
  4731. ───────────────────────────────────────────────────────────────────────────────
  4732.  
  4733.  Syntax
  4734.  
  4735.     A_SCAN(  <aTarget>,
  4736.              <expSearch>,
  4737.              [<idxPos>],
  4738.              [<nCount>] )    ->    nAbsPos
  4739.  
  4740.  Arguments
  4741.  
  4742.     <aTarget> The array to scan.
  4743.  
  4744.     <expSearch> An expression that evaluates to the same type as the
  4745.     <aTarget> array.
  4746.  
  4747.     <idxPos> is the first position to in the <aTarget> array to be
  4748.     scanned.  If not specified, the default value is the first element
  4749.     of the array.
  4750.  
  4751.     <nCount> is the number of elements to scan starting at <idxPos>.
  4752.     If not specified, elements are searched to the end of the array.
  4753.  
  4754.  Returns
  4755.  
  4756.     A_SCAN() returns an integer which is the absolute index pointer to
  4757.     the first element found that matches .  If no match is found
  4758.     A_SCAN() returns 0.  The <nAbsPos> can and should be used in any
  4759.     further references to that element (see example below).
  4760.  
  4761.  Description
  4762.  
  4763.     A_SCAN() is used to search a FlexFile array for a value.  A_SCAN()
  4764.     will return an error if <expSearch> evaluates to a different type
  4765.     than the <aTarget> array.
  4766.  
  4767.     Wrapping will occur if <nCount> goes beyond the current row
  4768.     pointed to by <idxPos>.  For example, if you have a two
  4769.     dimensional array with accounts represented by the first dimension
  4770.     and 12 prior period amounts in the second dimension, and you
  4771.     wanted to scan the first quarter (i.e.  3 periods) for a value,
  4772.     making <nCount> three times the number of accounts will "wrap"
  4773.     around three periods.  See the discussion on wrapping in the
  4774.     Arrays Chapter.
  4775.  
  4776.  Examples
  4777.  
  4778.     LOCAL ffArray, ptr, rows, cols
  4779.     
  4780.     rows = 5
  4781.     cols = 8
  4782.     
  4783.     // Declare a FlexFile floating point type array.
  4784.     ffArray = A_DECLARE( 'F', 5, 8 )
  4785.     
  4786.     // Store a couple of values.
  4787.     A_STORE( ffArray, 1234.56, A_( 3, 3 ) )
  4788.     A_STORE( ffArray, 789.10, A_(4, 4) )
  4789.     
  4790.     // Scan the entire array...
  4791.     ptr = A_SCAN( ffArray, 789.10 )
  4792.     ? A_RETRIEVE( ffArray, ptr )          // Result: 789.10
  4793.     
  4794.     // Scan starting at the first element in the fourth row.
  4795.     ? A_SCAN( ffArray, 1234.56, A( 4, 1 ) )   // Result: 0
  4796.     
  4797.     // Scan starting at the first element in the third row.
  4798.     ptr = A_SCAN( ffArray, 1234.56, A_( 3, 1 ) )
  4799.     ? A_RETRIEVE( ffArray, ptr )          // Result: 1234.56
  4800.     
  4801.     // Scan starting at the first element in the second row
  4802.     // but only count for one row.
  4803.     ? A_SCAN( ffArray, 1234.56, A_( 2, 1 ), cols )  // Result: 0
  4804.     
  4805.  
  4806.  
  4807. See Also: A_STORE() A_DECLARE() A_RETRIEVE()
  4808.  
  4809.  
  4810.  
  4811. ───────────────────────────────────────────────────────────────────────────────
  4812.  A_SCROLL()
  4813.  Scroll all or part of an array
  4814. ───────────────────────────────────────────────────────────────────────────────
  4815.  
  4816.  Syntax
  4817.  
  4818.     A_SCROLL(    <aTarget>,
  4819.                  [<idxPos>],
  4820.                  [<nCount>],
  4821.                  [<nMagnitude>] )
  4822.  
  4823.  Arguments
  4824.  
  4825.     <aTarget> is the array in which elements will be scrolled.
  4826.  
  4827.     <idxPos> is the first position to in the <aTarget> array to be
  4828.     scrolled.  If not specified, the default value is the first
  4829.     element.
  4830.  
  4831.     <nCount> is the number of elements to be scrolled starting at
  4832.     <idxPos>. If not specified, elements are scrolled to the end of
  4833.     the array.
  4834.  
  4835.     <nMagnitude> indicates how far and in what direction to scroll the
  4836.     array. A positive value scrolls the elements up (toward the
  4837.     beginning); a negative value scrolls the elements down (towards
  4838.     the end).  If no value is specified, the defined range is scrolled
  4839.     one element up.
  4840.  
  4841.  Returns
  4842.  
  4843.     None.
  4844.  
  4845.  Description
  4846.  
  4847.     A_SCROLL() scrolls all or a portion of a FlexFile array
  4848.     <nMagnitude> number of elements.  All elements at the end of the
  4849.     scroll are lost and the new elements are initialized to null.  Do
  4850.     not confuse FlexFile's null with Clipper's NIL.  A numeric null is
  4851.     0, a logical null is (.F.) and a string null is "".
  4852.  
  4853.     Wrapping will occur if <nCount> goes beyond the current row
  4854.     pointed to by <idxPos>.  For example, if you have a two
  4855.     dimensional array with accounts represented by the first dimension
  4856.     and 12 prior period amounts in the second dimension, and you
  4857.     wanted to scroll the first quarter (i.e. 3 periods) up in the
  4858.     array, making <nCount> three times the number of accounts will
  4859.     "wrap" the scroll.  Three periods worth of amounts will be
  4860.     scrolled out of the array and three periods of 0's will be filled.
  4861.     See the discussion on arrays in chapter 2 for more information on
  4862.     this feature.
  4863.  
  4864.  Examples
  4865.  
  4866.     LOCAL ffArray, accounts, periods
  4867.     
  4868.     accounts = 50
  4869.     periods = 12
  4870.     
  4871.     // Declare a FlexFile double precision type array.
  4872.     ffArray = A_DECLARE( 'D', periods, accounts )
  4873.     
  4874.     // Close out a quarter by scrolling three periods.
  4875.     // (i.e. scroll all accounts by 3 periods.)
  4876.     A_SCROLL( ffArray, , , -(accounts * 3) )
  4877.     
  4878.     // Insert a new account just in front of the 7th account.
  4879.     accounts++
  4880.     A_SIZE( @ffArray, periods, accounts )
  4881.     FOR x = 1 to periods
  4882.        A_SCROLL( ffArray, A_( x, 7 ), accounts - 7, -1 )
  4883.     NEXT
  4884.     
  4885.  
  4886.  
  4887. See Also: A_INS() A_DEL() A_SCAN()
  4888.  
  4889.  
  4890.  
  4891. ───────────────────────────────────────────────────────────────────────────────
  4892.  A_SIZE()
  4893.  Dynamically change the size or dimensions of an array
  4894. ───────────────────────────────────────────────────────────────────────────────
  4895.  
  4896.  Syntax
  4897.  
  4898.     A_SIZE(  @<aTarget>,
  4899.              <nElements>,
  4900.              [, <nElements>...] )   ->   lSuccess
  4901.  
  4902.  Arguments
  4903.  
  4904.     <aTarget> is the array to re-size.  It must be passed-by-
  4905.     reference.  A_SIZE() cannot resize binary type arrays.
  4906.  
  4907.     <nElements> are the new dimensions of the array.
  4908.  
  4909.  Returns
  4910.  
  4911.     A_SIZE() returns (.T.) if the function was successful, otherwise,
  4912.     it returns (.F.).   In addition, the aTarget array is modified.
  4913.  
  4914.  Description
  4915.  
  4916.     A_SIZE() modifies the dimensions of the @<aTarget>.  If the
  4917.     array is increased in size, the new elements will be added to the
  4918.     end of the array and assigned to null.  If the array is decreased
  4919.     in size, the data at the end of the array will be lost.
  4920.  
  4921.     You cannot change the number of dimensions with A_SIZE(), rather,
  4922.     you can change only their magnitude.
  4923.  
  4924.  Examples
  4925.  
  4926.     // Declare a two dimensional (L)ong integer array
  4927.     LOCAL rows, cols, x, y, z := 0
  4928.     
  4929.     rows = 10
  4930.     cols = 20
  4931.     aLong = A_DECLARE( "L", rows, cols )
  4932.     
  4933.     // Fill the array with increasing values.
  4934.     FOR x = 1 to rows
  4935.        FOR y = 1 to cols
  4936.           A_STORE( aLong, z++, A_( x, y ) )
  4937.        NEXT
  4938.     NEXT
  4939.     
  4940.     // Increase the size of the array by 10 rows
  4941.     A_SIZE( @aLong, rows + 10, cols )
  4942.     
  4943.     // Show some results.
  4944.     ? A_RETRIEVE( aLong, 10, 20 )      // Result: 200
  4945.     ? A_RETRIEVE( aLong, 11,  1 )      // Result:   0
  4946.     
  4947.  
  4948.  
  4949.  
  4950. See Also: A_ADD() A_DEL() A_INS()
  4951.  
  4952.  
  4953.  
  4954. ───────────────────────────────────────────────────────────────────────────────
  4955.  A_SORT()
  4956.  Sort all or part of an array in ascending or descending order
  4957. ───────────────────────────────────────────────────────────────────────────────
  4958.  
  4959.  Syntax
  4960.  
  4961.     A_SORT(  <aTarget>,
  4962.              [<idxPos>],
  4963.              [<nCount>],
  4964.              [<cOrder>] )
  4965.  
  4966.  Arguments
  4967.  
  4968.     <aTarget> is the array to be sorted.  A_SORT will not sort a Binary
  4969.     "logical" type array.
  4970.  
  4971.     <idxPos> is the position in the <aTarget> array to begin the sort.
  4972.     If not specified, the default value is one.
  4973.  
  4974.     <nCount> is the number of elements beginning at <idxPos> to sort.
  4975.     If not specified, all elements are sorted to the end of the row in
  4976.     the current dimension.
  4977.  
  4978.     <cOrder> is either "Ascending" or "Descending".  Only the first
  4979.     letter is significant.  If not specified, the sort is made
  4980.     "Ascending".
  4981.  
  4982.  Returns
  4983.  
  4984.     None.
  4985.  
  4986.  Description
  4987.  
  4988.     A_SORT() will sort all or part of a FlexFile array.  If <cOrder>
  4989.     is ascending, elements with higher values are stored at the top
  4990.     (beginning) of the array.  If <cOrder> is descending, elements
  4991.     with lower values are stored at the top of the array.
  4992.  
  4993.     Wrapping will occur if <nCount> goes beyond the current row
  4994.     pointed to by <idxPos>.
  4995.  
  4996.  Examples
  4997.  
  4998.     // Declare a two dimensional (C)haracter array
  4999.     LOCAL rows, cols, x, y, z
  5000.     
  5001.     rows = 10
  5002.     cols = 20
  5003.     z = 1
  5004.     aChar = A_DECLARE( "C", rows, cols )
  5005.     
  5006.     // Fill the array with increasing character values.
  5007.     FOR x = 1 to rows
  5008.        FOR y = 1 to cols
  5009.           z++
  5010.           A_STORE( aChar, chr(z), A_( x, y ) )
  5011.        NEXT
  5012.     NEXT
  5013.     
  5014.     // Sort the first row in descending order
  5015.     A_SORT( aChar, A_( 1, 1 ), cols, 'D' )
  5016.     
  5017.     // Show the results
  5018.     ? A_RETRIEVE( aChar, A_( 1, 1 ) )    // Result: 
  5019.     ? A_RETRIEVE( aChar, A_( 1, 20) )    // Result: 
  5020.     
  5021.  
  5022. See Also: A_SCAN()
  5023.  
  5024.  
  5025.  
  5026. ───────────────────────────────────────────────────────────────────────────────
  5027.  A_STORE()
  5028.  Store an expression into an element of an array
  5029. ───────────────────────────────────────────────────────────────────────────────
  5030.  
  5031.  Syntax
  5032.  
  5033.     A_STORE( <aTarget>,
  5034.              <expValue>,
  5035.              <idxPos> )    ->    lSuccess
  5036.  
  5037.  Arguments
  5038.  
  5039.     <aTarget> is the array in which to store <expValue>.
  5040.  
  5041.     <expValue> is any simple Clipper expression that evaluates to the
  5042.     same type as the array.
  5043.  
  5044.     <idxPos> is the index to the element whose value will become
  5045.     <expValue>.
  5046.  
  5047.  Returns
  5048.  
  5049.     A_STORE() returns (.T.) if successful, otherwise, (.F.).
  5050.  
  5051.  Description
  5052.  
  5053.     A_STORE() stores a value in a FlexFile type array.  The value
  5054.     being stored must be of the same type as that of the array.
  5055.     Storing a value with a different type than the array is considered
  5056.     an error and A_STORE() will return (.f.).
  5057.  
  5058.     ┌────────────────────────── WARNING ───────────────────────────┐
  5059.     │ You must use A_KILL() to release the data that has been type │
  5060.     │ A_STORE()d to a string type array before allowing the array  │
  5061.     │ to fall out of scope.                                        │
  5062.     └──────────────────────────────────────────────────────────────┘
  5063.  
  5064.  Examples
  5065.  
  5066.     // Declare a two dimensional (C)haracter array
  5067.     LOCAL rows, cols, x, y, z
  5068.     
  5069.     rows = 10
  5070.     cols = 20
  5071.     z = 1
  5072.     aChar = A_DECLARE( "C", rows, cols )
  5073.     
  5074.     // Fill the array with increasing character values.
  5075.     FOR x = 1 to rows
  5076.        FOR y = 1 to cols
  5077.           z++
  5078.           A_STORE( aChar, chr(z), A_( x, y ) )
  5079.        NEXT
  5080.     NEXT
  5081.     
  5082.     // Print out the results: All ASCII characters from one
  5083.     // to 200.  If you run this program it will beep an sqauk
  5084.     // and generally look ugly.
  5085.     FOR x = 1 to rows
  5086.        FOR y = 1 to cols
  5087.           z++
  5088.           ? A_RETRIEVE( aChar, A_( x, y ) )
  5089.        NEXT
  5090.     NEXT
  5091.     
  5092.  
  5093.  
  5094. See Also: A_KILL() A_FILL() A_RETRIEVE()
  5095.  
  5096.  
  5097.  
  5098. ───────────────────────────────────────────────────────────────────────────────
  5099.  A_TYPE()
  5100.  Return the type of an array
  5101. ───────────────────────────────────────────────────────────────────────────────
  5102.  
  5103.  Syntax
  5104.  
  5105.     A_TYPE( <aTarget> )   ->   cType
  5106.  
  5107.  Arguments
  5108.  
  5109.     <aTarget> is the array whose type is returned.
  5110.  
  5111.  Returns
  5112.  
  5113.     A_TYPE() returns the type of the <aTarget> as a character
  5114.     string.
  5115.  
  5116.  Description
  5117.  
  5118.     A_TYPE() returns the type of a FlexFile array.  If the array is of
  5119.     integer type and was declared as unsigned, then a "U" will precede
  5120.     the type.
  5121.  
  5122.     The return value is a character string such as "L" for a long
  5123.     integer or "UL" for an unsigned long integer.
  5124.  
  5125.     Appendix C lists all the array types and sizes.
  5126.  
  5127.  
  5128.  Examples
  5129.  
  5130.     // Setup seven variables of differing array types.
  5131.     LOCAL aLogical  ,;
  5132.           aChar     ,;
  5133.           aTiny     ,;
  5134.           auTiny    ,;
  5135.           aInteger  ,;
  5136.           auInteger ,;
  5137.           aLong     ,;
  5138.           auLong    ,;
  5139.           aString   ,;
  5140.           aFloat    ,;
  5141.           aDouble
  5142.     
  5143.     // Declare an array for each possible type.
  5144.     aLogical  = A_DECLARE( 'B', 10 )
  5145.     aChar     = A_DECLARE( 'C', 10 )
  5146.     aTiny     = A_DECLARE( 'T', 10 )
  5147.     auTiny    = A_DECLARE( 'UT', 10 )
  5148.     aInteger  = A_DECLARE( 'I', 10 )
  5149.     auInteger = A_DECLARE( 'UI', 10 )
  5150.     aLong     = A_DECLARE( 'L', 10 )
  5151.     auLong    = A_DECLARE( 'UL', 10 )
  5152.     aString   = A_DECLARE( 'S', 10 )
  5153.     aFloat    = A_DECLARE( 'F', 10 )
  5154.     aDouble   = A_DECLARE( 'D', 10 )
  5155.     
  5156.     // Show the type of each array
  5157.     ? A_TYPE( aLogical )              //  Result: B
  5158.     ? A_TYPE( aChar    )              //  Result: C
  5159.     ? A_TYPE( aTiny    )              //  Result: T
  5160.     ? A_TYPE( auTiny   )              //  Result: UT
  5161.     ? A_TYPE( aInteger )              //  Result: I
  5162.     ? A_TYPE( auInteger)              //  Result: UI
  5163.     ? A_TYPE( aLong    )              //  Result: L
  5164.     ? A_TYPE( auLong   )              //  Result: UL
  5165.     ? A_TYPE( aString  )              //  Result: S
  5166.     ? A_TYPE( aFloat   )              //  Result: F
  5167.     ? A_TYPE( aDouble  )              //  Result: D
  5168.     
  5169.  
  5170.  
  5171. See Also: A_DECLARE()
  5172.  
  5173. Error Codes Introduction
  5174.  
  5175.    Changes:
  5176.  
  5177.    The FlexFile error system has been changed significatly in
  5178.    releases after 1.01.  The main differences are that:
  5179.  
  5180.      1. Any call to any FlexFile V_xxx() function will reset
  5181.      the V_ERROR() to zero.  Any call to any A_xxx() function
  5182.      will reset the A_ERROR() to zero.  This prevents an error
  5183.      setting from appearing in a context other than what
  5184.      caused it.
  5185.  
  5186.      2. Two error codes are now maintained.  One for the V_xxx()
  5187.      functions and the other for the A_xxx() functions.
  5188.  
  5189.      3. Calling either V_ERROR() or A_ERROR() no longer resets
  5190.      the error code.  Therefore, you can now make multiple calls
  5191.      to the desired error reporting routine without loosing the
  5192.      error.
  5193.  
  5194.  
  5195.    General Information
  5196.  
  5197.    The FlexFile error system is accessed by either of the two
  5198.    functions A_ERROR() or V_ERROR().  These functions can be
  5199.    accessed from the debugger's expression window or placed
  5200.    directly in your code.  Of course, if you plan to use either
  5201.    function from the debugger you must refer to them with either
  5202.    the EXTERNAL command or explicitly within your code in order
  5203.    for the LINKER to include them in your application.
  5204.  
  5205.    The error functions will report the last error that
  5206.    was trapped by FlexFile as a numeric integer.  For example, if
  5207.    you attempt to V_USE() a file which is already being used
  5208.    exclusivly by another user on a network, V_USE() will return a
  5209.    -1 and V_ERROR() will return 5052.  However, if you do not
  5210.    test the V_ERROR() return value until after you try to
  5211.    V_REPLACE() a value (remember no file was opened), then
  5212.    V_ERROR() will return 7301 indicatating a V_REPLACE() error.
  5213.  
  5214.    Ignore any numbers in the 10's and 1'n place in the return
  5215.    value from the error functions;  these are used by the
  5216.    FlexFile support staff.  So, for example, 7301 and 7302 both
  5217.    refer to the 7300 class of error.
  5218.  
  5219.    These functions, when called, reset the error value to zero
  5220.    which indicates that no error has occurred.
  5221.  
  5222. See Also: V_ERROR() A_ERROR()
  5223.  
  5224. ──────────────────────────────────────────────────────────────────────────────
  5225. Error 0100      Not an array.lib type array.
  5226. ──────────────────────────────────────────────────────────────────────────────
  5227.  
  5228.  
  5229.    A parameter passed is not a FlexFile strongly typed array but
  5230.    should have been.
  5231.  
  5232.    The most usual cause of this problem is that a parameter is
  5233.    out of order in the parameter list of a FlexFile function or a
  5234.    Clipper array was passed instead of a FlexFile type array.
  5235.  
  5236. See Also: A_DECLARE()
  5237.  
  5238. ──────────────────────────────────────────────────────────────────────────────
  5239. Error 0300      Invalid A_DECLARE() dimensions
  5240. ──────────────────────────────────────────────────────────────────────────────
  5241.  
  5242.  
  5243.    An attempt was made to declare an array with greater than six
  5244.    dimensions or zero dimensions.
  5245.  
  5246. See Also: A_DECLARE()
  5247.  
  5248.  
  5249. ──────────────────────────────────────────────────────────────────────────────
  5250. Error 0400      Attempt to address an out of bounds element.
  5251. ──────────────────────────────────────────────────────────────────────────────
  5252.  
  5253.  
  5254.    An attempt was made to address an element which is outside  of
  5255.    the bounds of the FlexFile array.
  5256.  
  5257.    For example,  if you declare a single dimensional array with
  5258.    twenty elements and then try to access the twenty first
  5259.    element (or an element in the second or greater dimension),
  5260.    A_ERROR() will return 400.
  5261.  
  5262. See Also: A_RETRIEVE() A_DECLARE()
  5263.    
  5264.  
  5265. ──────────────────────────────────────────────────────────────────────────────
  5266. Error 0500      Attempt to declare an array larger than 65535 bytes.
  5267. ──────────────────────────────────────────────────────────────────────────────
  5268.  
  5269.  
  5270.    Because the elements of different FlexFile array types require
  5271.    different amounts of space, you must look at each array type
  5272.    to determine the maximum number of elements possible.
  5273.  
  5274.    The limiting factore in FlexFile arrays of every type is 65535
  5275.    bytes.  So, for example, an integer array which requires only
  5276.    two bytes per element will reach this limit when you attempt
  5277.    to declare an integer array of slightly more than 32,000
  5278.    elements.
  5279.  
  5280.    See the reference to A_DECLARE() for a table of array type and
  5281.    required sizes per element.
  5282.  
  5283. See Also: A_DECLARE()
  5284.  
  5285. ──────────────────────────────────────────────────────────────────────────────
  5286. Error 0600      Attempt to declare an array with an invalid type.
  5287. ──────────────────────────────────────────────────────────────────────────────
  5288.  
  5289.  
  5290.    The arrays type must be one that FlexFile recognizes.  These
  5291.    are listed in the A_DECLARE() function reference.
  5292.  
  5293. See Also: A_DECLARE()
  5294.  
  5295. ──────────────────────────────────────────────────────────────────────────────
  5296. Error 0700      Attempt to declare an array with invalid dimensions.
  5297. ──────────────────────────────────────────────────────────────────────────────
  5298.  
  5299.  
  5300.    A FlexFile type array may have a minimum of one and a maximum of
  5301.    six dimensions.
  5302.  
  5303. See Also: A_DECLARE()
  5304.  
  5305. ──────────────────────────────────────────────────────────────────────────────
  5306. Error 0800      Out of memory on an attempt to declare an array
  5307. ──────────────────────────────────────────────────────────────────────────────
  5308.  
  5309.  
  5310.    In S'87 and the initial release of Clipper 5.0 it is a fatal
  5311.    error when an attempt is made to declare an array larger than
  5312.    available memory.  However, this is a bug in 5.0 and when
  5313.    fixed this error will indicate that condition and the error
  5314.    system will be automatically called.
  5315.  
  5316. See Also: A_DECLARE()
  5317.  
  5318. ──────────────────────────────────────────────────────────────────────────────
  5319. Error 2000      Array type incompatible with function called.
  5320. ──────────────────────────────────────────────────────────────────────────────
  5321.  
  5322.  
  5323.    The array function called cannot operate on the type of the
  5324.    array passed.  For example, if you pass A_SORT() a binary type
  5325.    array, no sort will be performed and this error will be set.
  5326.  
  5327. See Also: A_SORT() A_SCAN()
  5328.  
  5329.  
  5330. ──────────────────────────────────────────────────────────────────────────────
  5331. Error 2100      Function called is not valid on binary arrays.
  5332. ──────────────────────────────────────────────────────────────────────────────
  5333.  
  5334.  
  5335.    Binary (logical) arrays are not supported by many of the FlexFile
  5336.    array functions.  For example, you cannot A_SCAN() an array for a
  5337.    logical (.t.) or (.f.) and you cannot A_SORT().  The FlexFile
  5338.    array functions which operate on binary arrays are:
  5339.  
  5340.                 A_STORE()
  5341.                 A_RETRIEVE()
  5342.                 A_LEN()
  5343.                 A_TYPE()
  5344.  
  5345.  
  5346. ──────────────────────────────────────────────────────────────────────────────
  5347. Error 2200      Divide by zero in a FlexFile array math function.
  5348. ──────────────────────────────────────────────────────────────────────────────
  5349.  
  5350.  
  5351.    FlexFile's math functions such as A_DIVIDE() are protected against
  5352.    a programmer error of division by zero.  In the event this error
  5353.    occurs, the division results in a zero value and this error is
  5354.    flagged.
  5355.  
  5356. See Also: A_DIVIDE()
  5357.  
  5358. ──────────────────────────────────────────────────────────────────────────────
  5359. Error 2300      A_COPY() used with incompatable array types
  5360. ──────────────────────────────────────────────────────────────────────────────
  5361.  
  5362.  
  5363.    An attempt was made to use A_COPY() on two different array types.
  5364.    A_COPY() must be performed on arrays of the same type.
  5365.  
  5366.  
  5367. See Also: A_COPY()
  5368.  
  5369. ──────────────────────────────────────────────────────────────────────────────
  5370. Error 3000      Bad or missing parameter in array function.
  5371. ──────────────────────────────────────────────────────────────────────────────
  5372.  
  5373.  
  5374.    A parameter was passed to a FlexFile array function that is not
  5375.    the correct type or a parameter is required that was not passed.
  5376.  
  5377.    The most usual cause of this problem is that a parameter is
  5378.    out of order in the parameter list of a FlexFile function or a
  5379.    parameter was inadvertently omitted.
  5380.  
  5381.  
  5382. ──────────────────────────────────────────────────────────────────────────────
  5383. Error 3100      A_SIZE() error in dimensions.
  5384. ──────────────────────────────────────────────────────────────────────────────
  5385.  
  5386.  
  5387.    A_SIZE() cannot change the number of an arrays dimensions, rather,
  5388.    it can only change the magnitude of each dimension.  An attempt
  5389.    was made to change the number of dimensions.
  5390.  
  5391.  
  5392. See Also: A_SIZE() A_ADD()
  5393.  
  5394. ──────────────────────────────────────────────────────────────────────────────
  5395. Error 5000      Unable to open file.
  5396. ──────────────────────────────────────────────────────────────────────────────
  5397.  
  5398.  
  5399.    This error can result from many different situations:
  5400.  
  5401.       Disk access denied (disk full).
  5402.       Create error.
  5403.       Impropper file name (directory does not exist).
  5404.       File opened exclusively by other user.
  5405.  
  5406.  
  5407. See Also: V_USE() V_VLF2FILE() network.ngo:Network Programming
  5408.  
  5409. ──────────────────────────────────────────────────────────────────────────────
  5410. Error 5200      Attempt to lock header failed.
  5411. ──────────────────────────────────────────────────────────────────────────────
  5412.  
  5413.  
  5414.    This error occurs when V_USE() fails to get a lock on the header
  5415.    of the DBV file.
  5416.  
  5417. See Also: V_USE() "Error 5000"
  5418.  
  5419. ──────────────────────────────────────────────────────────────────────────────
  5420. Error 5300      Out of memory.
  5421. ──────────────────────────────────────────────────────────────────────────────
  5422.  
  5423.  
  5424.    This error occurs when FlexFile fails to allocate memory using
  5425.    Clipper's extend system.  Because FlexFile requires very little
  5426.    memory, this is an unusual error and indicates extremely low memory
  5427.    conditions.
  5428.  
  5429.  
  5430.  
  5431. ──────────────────────────────────────────────────────────────────────────────
  5432. Error 6000      Invalid or missing parameter.
  5433. ──────────────────────────────────────────────────────────────────────────────
  5434.  
  5435.  
  5436.    This error occurs whenever FlexFile detects a parameter of the
  5437.    wrong type or a missing parameter when one is required.
  5438.  
  5439.    The most usual cause of this problem is that a parameter is
  5440.    out of order in the parameter list of a FlexFile function.
  5441.  
  5442. ──────────────────────────────────────────────────────────────────────────────
  5443. Error 6200      Bad pointer-field passed.
  5444. ──────────────────────────────────────────────────────────────────────────────
  5445.  
  5446.  
  5447.    FlexFile generates a six byte character string which points to
  5448.    data stored in a DBV file.  If you attempt to use anything but
  5449.    a FlexFile generated pointer-field in an attempt to access data
  5450.    in a DBV file, this error will be generated.  The single exception
  5451.    to this rule is an empty pointer-field which must be six (or more)
  5452.    spaces.
  5453.  
  5454.  
  5455. ──────────────────────────────────────────────────────────────────────────────
  5456. Error 6300      Invalid data type in v_replace().
  5457. ──────────────────────────────────────────────────────────────────────────────
  5458.  
  5459.  
  5460.    The valid data types for V_REPLACE() are defined in the V_REPLACE()
  5461.    function reference.  If FlexFile encounters a type which is not
  5462.    amoung these valid types, this error will be generated.
  5463.  
  5464.    In addition, if you make the mistake of using a pointer-field which
  5465.    points into one file as a pointer-field for a different file, FlexFile
  5466.    will again generate this error.  This is because the pointer-field
  5467.    is pointing to something other than the header which FlexFile pre-
  5468.    pends to each field.
  5469.  
  5470.  
  5471. ──────────────────────────────────────────────────────────────────────────────
  5472. Error 6400      Proclip(tm) window is not a compatible version.
  5473. ──────────────────────────────────────────────────────────────────────────────
  5474.  
  5475.  
  5476.    An attempt was made to restore a Proclip window which has been
  5477.    stored to a DBV file while using an incompatible (most probably newer)
  5478.    version of Proclip.
  5479.  
  5480.    You will need a newer version of FlexFile to accomodate the new
  5481.    Proclip window type.
  5482.  
  5483.  
  5484. ──────────────────────────────────────────────────────────────────────────────
  5485. Error 6500      VLF length exceeds Clipper's maximum 65535 bytes.
  5486. ──────────────────────────────────────────────────────────────────────────────
  5487.  
  5488.  
  5489.    In certain circumstances it is possible to create a VLF that is
  5490.    larger than 64K.  The V_STUFF() function is capable of increasing
  5491.    the size of a field with no regard for memory, and the V_FILE2VLF()
  5492.    function will easily create fields that are extremely large.
  5493.  
  5494.    If you then attempt to V_RETRIEVE() this data, this error will be
  5495.    set and V_RETRIEVE() will fail.
  5496.  
  5497. See Also: V_RETRIEVE() V_STUFF() dbvfunc.ngo V_REPLACE()
  5498.  
  5499. ──────────────────────────────────────────────────────────────────────────────
  5500. Error 6700      Error in V_RETRIEVE().  Array corrupted.
  5501. ──────────────────────────────────────────────────────────────────────────────
  5502.  
  5503.  
  5504.    An attempt was made to retrieve an array from a DBV but the array
  5505.    was found to be corrupted.  V_PACK()ing the file is recommended.
  5506.  
  5507.  
  5508. See Also: V_RETRIEVE()
  5509.  
  5510. ──────────────────────────────────────────────────────────────────────────────
  5511. Error 7100      Write error.  The disk may be full.
  5512. ──────────────────────────────────────────────────────────────────────────────
  5513.  
  5514.  
  5515.    An attemt to write data failed.  If the file was in use in shared
  5516.    mode, this error can still occur after the lock has been secured.
  5517.    The most likely cause for this error is no remaining disk space.
  5518.  
  5519.  
  5520. ──────────────────────────────────────────────────────────────────────────────
  5521. Error 7200      Record locking time out.
  5522. ──────────────────────────────────────────────────────────────────────────────
  5523.  
  5524.  
  5525.    This is an error code for future versions of FlexFile.
  5526.  
  5527.  
  5528. ──────────────────────────────────────────────────────────────────────────────
  5529. Error 7300      File not open in currently V_SELECTed() area.
  5530. ──────────────────────────────────────────────────────────────────────────────
  5531.  
  5532.    Attempt was made to access a DBV file in a FlexFile work area
  5533.    that does not have a file open.  For example,
  5534.  
  5535.       V_CLOSE()
  5536.       V_REPLACE( "Try and put this away", ptr_fld )
  5537.  
  5538. See Also: V_SELECT() V_ALIAS()
  5539.  
  5540. ──────────────────────────────────────────────────────────────────────────────
  5541. Error 7400      Selected area is out of bounds.  See v_files().
  5542. ──────────────────────────────────────────────────────────────────────────────
  5543.  
  5544.  
  5545.    You can only V_SELECT() an area within the current V_FILES() setting.
  5546.    The default setting for the maximum number of areas is 10.
  5547.  
  5548. See Also: V_FILES() V_SELECT()
  5549.  
  5550. ──────────────────────────────────────────────────────────────────────────────
  5551. Error 7500      Unknown alias.
  5552. ──────────────────────────────────────────────────────────────────────────────
  5553.  
  5554.  
  5555.    An attempt was made to V_SELECT() (or pass a function that accepts
  5556.    an area as a parameter) an illegal or unknown alias.
  5557.  
  5558. See Also: V_ALIAS() V_SELECT() V_USE()
  5559.  
  5560. ─────────────────────────────────────────────────────────────────────────────
  5561. Error 7600      Illegal attempt to reset V_FILES() or V_BUFFERS
  5562. ─────────────────────────────────────────────────────────────────────────────
  5563.  
  5564.  
  5565.    An attempt was made to set V_FILES() or V_BUFFERS() when there was at
  5566.    least one DBV file open.  You must first close all DBV files before
  5567.    attempting to use these functions.
  5568.  
  5569. See Also: V_FILES() V_BUFFERS()
  5570.  
  5571. ─────────────────────────────────────────────────────────────────────────────
  5572. Error 7700      Invalid V_RETRIEVE() substring parameters.
  5573. ─────────────────────────────────────────────────────────────────────────────
  5574.  
  5575.  
  5576.    When using V_RETRIEVE() to retrieve only part of a VLF, the parameters
  5577.    representing the bounds of the string to retrieve were invalid.
  5578.  
  5579. See Also: V_RETRIEVE()
  5580.  
  5581. ──────────────────────────────────────────────────────────────────────────────
  5582. Error 8000      No areas remain.  See v_files() to increase the quantity of areas.
  5583. ──────────────────────────────────────────────────────────────────────────────
  5584.  
  5585.  
  5586.    An attempt was made to V_USE() with the "NEW" modifier or V_SELECT(0)
  5587.    when all available areas are in use.  The solution to this problem
  5588.    is to increase your maximum FlexFile work areas with the V_FILES()
  5589.    function.
  5590.  
  5591. See Also: V_FILES() V_SELECT() V_USE()
  5592.  
  5593. ──────────────────────────────────────────────────────────────────────────────
  5594. Error 8100      Not a VLF type file.
  5595. ──────────────────────────────────────────────────────────────────────────────
  5596.  
  5597.  
  5598.    Attempt was made to V_USE() a file that is not recognizable as a
  5599.    FlexFile type file.
  5600.  
  5601. See Also: V_USE()
  5602.  
  5603. ──────────────────────────────────────────────────────────────────────────────
  5604. Error 8200      File read error.
  5605. ──────────────────────────────────────────────────────────────────────────────
  5606.  
  5607.    This error is possible if an exclusive lock has been imposed
  5608.    by another work station on a network.
  5609.  
  5610. See Also: V_EXCLUSIV()
  5611.  
  5612. ──────────────────────────────────────────────────────────────────────────────
  5613. Error 8300      Unknown data type.  Possibly using a pointer-field from wrong work area.
  5614. ──────────────────────────────────────────────────────────────────────────────
  5615.  
  5616.  
  5617.    The valid data types for V_REPLACE() and V_RETRIEVE() are defined
  5618.    in the V_REPLACE() function reference.  If FlexFile encounters a
  5619.    type which is not amoung these valid types, this error will be
  5620.    generated. For example, using V_RETRIEVE() to try to fetch a Summer
  5621.    87 array will create this error. Use V_FILLARR() instead.
  5622.  
  5623.    In addition, if you make the mistake of using a pointer-field which
  5624.    points into one file as a pointer-field for a different file, FlexFile
  5625.    will again generate this error.  This is because the pointer-field
  5626.    is pointing to something other than the header which FlexFile pre-
  5627.    pends to each field.
  5628.  
  5629.  
  5630. ──────────────────────────────────────────────────────────────────────────────
  5631. Error 8400      Attempt to V_RETRIEVE a Proclip window.
  5632. ──────────────────────────────────────────────────────────────────────────────
  5633.  
  5634.    An attempt was made to V_RETRIEVE() a Proclip window.  Use
  5635.    V_WNDCREAT() to create a Proclip window that has been stored
  5636.    to a DBV file.
  5637.  
  5638.  
  5639. See Also: V_WNDCREAT()
  5640.  
  5641. ──────────────────────────────────────────────────────────────────────────────
  5642. Error 9000      Undetermined error in seek for deleted space.
  5643. ──────────────────────────────────────────────────────────────────────────────
  5644.  
  5645.    Unfortunately, this spells disaster and is usually caused by a
  5646.    corrupted DBV file.  However, the FlexFile scheme is based on
  5647.    a very solid principal.  That is, if your DBF file holding the
  5648.    pointer-fields into the DBV file is intact, the V_RETRIEVE()
  5649.    function will almost invariably still retrieve data from any
  5650.    field that has not yet been corrupted.
  5651.  
  5652.    So, disaster recovery is as simple as creating a new DBV file
  5653.    in a new FlexFile work area and V_REPLACE()ing data into the
  5654.    new area with the data V_RETRIEVE()d from the corrupted area.
  5655.  
  5656.    Remember to test for V_TYPE() on the pointer-field because if
  5657.    it encounters a corrupted portion of the file, it will return
  5658.    an "U"ndefined regardless of the data type stored in that
  5659.    particular field.
  5660.  
  5661.  
  5662.  
  5663.